AOP与动态代理浅析

AOP是Spring最重要的功能之一,通过切面实现对象增强,降低对业务的侵入,把核心业务代码和周边公共代码解耦。

比如,在方法上加上@Transactional注解,就能够使用Spring的默认事务机制,通过TransactionInterceptor实现切面,在before时提供调用点,决定业务方法是否需要开启一个新的独立事务,在after时确定事务被提交、回滚、还是继续运行。这就不需要在每个方法里都重复写一遍事务操作的相关代码。

 

AOP通过动态创建代理对象实现,动态代理的方式分为JDK动态代理和CGLIB,以下简述这两种代理方式的使用

JDK动态代理

先看使用,需要通过Proxy类的 newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法来生成指定类型的代理对象,该类必须有实现的接口。

 

 使用举例:

public interface IUserInfoService {
Integer saveUserInfo(UserInfo userInfo);
}

 

public class UserInfoServiceImpl implements IUserInfoService {
@Override
public Integer saveUserInfo(UserInfo userInfo) {
System.out.println(userInfo.getUserName());
return userInfo.getId();
}
}
public static void main(String[] arg) {
UserInfo userInfo = new UserInfo();
userInfo.setId(1);
userInfo.setUserName("小明");

IUserInfoService userInfoService = new UserInfoServiceImpl();
//创建代理对象
IUserInfoService userInfoServiceProxy = (IUserInfoService) Proxy.newProxyInstance(userInfoService.getClass().getClassLoader(),
       //传入要代理的接口
userInfoService.getClass().getInterfaces(),
       //传入InvocationHandler接口实现类,提供切面逻辑
(proxy, method, args) -> {
          //实现增强
System.out.println("方法执行前");
Object obj = method.invoke(userInfoService, args);
System.out.println("方法执行后");
return obj;
});
System.out.println("Id:" + userInfoServiceProxy.saveUserInfo(userInfo));
}

 

主要原理是,通过代理类生成器ProxyGenerator直接生成代理类的Class文件而不需要再通过虚拟机再加载。

生成过程是根据Class文件结构拼接而成的,源码分析可以参考:https://www.cnblogs.com/liuyun1995/p/8157098.html

生成的代理类默认继承Porxy类,实现传入的接口。

这也就解释了被代理的类需要实现接口,才能让代理类收集到需要代理的方法。

拿到Class文件后,通过getConstrucator()方法创建只有InvocationHandler类型参数的构造函数,然后通过newInstance()方法生成代理对象实例。

代理方法会调用InvocationHandler的invoke()方法,为被代理类的方法实现增强。

 

CGLIB

CGLIB全称Code Generation Library,意为代码生成库。

CGLIB代理也是通过生成字节码文件生成新的代理对象,它的思想是通过继承代理类的非final方法,然后在重写方法时写入增强。

 

Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserInfoServiceImpl.class);
enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
  //实现增强
System.out.println("方法执行前");
Object obj = methodProxy.invokeSuper(o, objects);
System.out.println("方法执行后");
return obj;
});
//创建被代理对象
UserInfoServiceImpl userInfoService = (UserInfoServiceImpl) enhancer.create();
System.out.println("Id:" + userInfoService.saveUserInfo(userInfo));

Enhancer相当于JDK代理中的Proxy,但它既能代理普通类,也能够代理接口。

 

这两种代理相比之下,一般认为CGLIB代理方式创建慢执行快,JDK动态代理创建快执行较慢。

AOP

Spring根据策略判断使用JDK动态代理和还是CGLIB

@Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    // config.isOptimize()是否强制使用优化代理策略,默认false

    // config.isProxyTargetClass()  目标类本身被代理而不是目标类的接口

    // hasNoUserSuppliedProxyInterfaces() 是否存在代理接口

        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class: " +
                        "Either an interface or a target is required for proxy creation.");
            }
       //目标是接口或是代理类时,使用JDK动态代理 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else {
       //默认使用JDK动态代理 return new JdkDynamicAopProxy(config); } }
posted @ 2019-12-29 17:44  _Gradually  阅读(690)  评论(0编辑  收藏  举报