jdk动态代理 注解的获取

一、使用场景

  根据方法或者类上是否有指定的注解,进行业务增强。例如:手写transactional注解,实现声明式事务

  1、自定义transaction注解

/**
 * 描述 自定义事务注解
 *
 * @author lwb
 * @since 2020/7/8
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Inherited
public @interface Transactional {
}
View Code

  2、业务代码:定义用户服务接口,实现用户服务接口,在实现类的方法上标注@transaction注解

/**
 * 描述 用户服务接口类
 *
 * @author lwb
 * @since 2020/7/8
 */
public interface UserService {

    void doSomething(String thing);
}

public class UserServiceImpl implements UserService {
    @Override
    @Transactional
    public void doSomething(String thing) {
        System.out.println("do something : " + thing);
    }
}
View Code

  3、动态代理工厂:生成对象的jdk动态代理

public static Object getJdkProxy(Object object){
        return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),
                (proxy, method, args) -> {
                    Object result;
                    if(method.isAnnotationPresent(Transactional.class) || method.getDeclaringClass().isAnnotationPresent(Transactional.class)){
                        try {
                            System.out.println("开启事务");
                            result = method.invoke(object, args);
                            System.out.println("提交事务");
                        }catch (Exception e){
                            System.out.println("回滚事务");
                            throw e;
                        }
                    }else{
                        result = method.invoke(object, args);
                    }

                    return result;
                });
    }
View Code

  4、测试

/**
 * 描述
 *
 * @author lwb
 * @since 2020/7/8
 */
public class ProxyTest {

    @Test
    public void testJdkProxy(){
        UserService userService = new UserServiceImpl();
        UserService jdkProxy = (UserService) ProxyFactory.getJdkProxy(userService);
        jdkProxy.doSomething("eat");
    }
}
View Code

  5、校验测试结果

  

  发现并未打印事务信息。不符合预期结果。

 二、问题分析

   明明在实现类的方法上标注了Transaction注解,为什么在增强中没有获取到Transaction注解?分析jdk动态代理的原理可知:该method是UserService接口的doSomething方法,method.getDeclaringClass()获取的是UserSevice接口,在doSomething方法与UserService接口上并未使用Transaction注解,所以没打印事务信息。

三、解决方案

  根据问题分析,可以得出以下两种解决方案:

  1、在UserService接口上或者UserService接口中的doSomething上标注Transaction注解

/**
 * 描述 用户服务接口类
 *
 * @author lwb
 * @since 2020/7/8
 */
public interface UserService {

    @Transactional
    void doSomething(String thing);
}

/**
 * 描述 用户服务实现类
 *
 * @author lwb
 * @since 2020/7/8
 */
public class UserServiceImpl implements UserService {
    @Override
    public void doSomething(String thing) {
        System.out.println("do something : " + thing);
    }
}
View Code

     测试结果

     

  测试通过,符合预期。这种将注解标注在接口中,则所有的实现类,都会进行增强

  2、修改代理工厂方法,获取实现类与实现类的方法,判断是否标注注解

   业务代码还原:去除接口方法上的注解,将注解添加到实现类的方法上

/**
 * 描述 用户服务接口类
 *
 * @author lwb
 * @since 2020/7/8
 */
public interface UserService {

    void doSomething(String thing);
}



/**
 * 描述 用户服务实现类
 *
 * @author lwb
 * @since 2020/7/8
 */
public class UserServiceImpl implements UserService {
    @Override
    @Transactional
    public void doSomething(String thing) {
        System.out.println("do something : " + thing);
    }
}
View Code

  修改代理工厂的方法

public static Object getJdkProxy(Object object){
        return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),
                (proxy, method, args) -> {
                    Object result;
                    Method targetMethod = object.getClass().getMethod(method.getName(), method.getParameterTypes());
                    if(method.isAnnotationPresent(Transactional.class) || method.getDeclaringClass().isAnnotationPresent(Transactional.class)
                            || object.getClass().isAnnotationPresent(Transactional.class) || targetMethod.isAnnotationPresent(Transactional.class)){
                        try {
                            System.out.println("开启事务");
                            result = method.invoke(object, args);
                            System.out.println("提交事务");
                        }catch (Exception e){
                            System.out.println("回滚事务");
                            throw e;
                        }
                    }else{
                        result = method.invoke(object, args);
                    }

                    return result;
                });
    }
View Code

 测试结果

测试通过,符合预期。标注在实现类上的注解,只在实现类生效

posted on 2020-07-08 11:52  DamonBlogs  阅读(1312)  评论(0编辑  收藏  举报

导航