Spring源码分析:AOP代理

Spring源码分析:AOP代理

  • Aop使用
    • Aop切面
    • 接口
    • 接口实现
    • 运行
  • JDK代理和Cglib代理
    • JDK代理与Cglib代理区别
  • 源码分析
    • 获取代理对象
    • 生成代理对象
    • 为什么JDK动态代理必须是接口

Aop使用

Aop切面

@Configuration
@Aspect
public class AopTime {

    @Around("execution(* gdut.ff.aop.*.*(..))")
    public Object around(ProceedingJoinPoint joinPoint) {
        long start = System.currentTimeMillis();
        Object obj = null;
        try {
            obj = joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("消耗时间:" + (end - start) + " interface name is : " + joinPoint.getTarget());
        return obj;
    }

}

接口

public interface ITestService {

    public void test();

}

接口实现

@Service
public class TestServiceImpl implements ITestService{
    @Override
    public void test() {
        System.out.println("Test");
    }
}

运行

@EnableAspectJAutoProxy
@ComponentScan("gdut.ff.aop")
public class TestAop {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestAop.class);
        TestServiceImpl  testServiceImpl = context.getBean("testServiceImpl",TestServiceImpl.class);
        testServiceImpl.test();
    }
}

JDK代理和Cglib代理

JDK代理与Cglib代理区别

JDK代理是基于接口实现的。Cglib代理不需要实现接口

源码分析

接下来,我们一步步解析Spring是如何代理对象的。

获取代理对象

先来看看context.getBean()方法是如何获取到代理对象的。

AbstractBeanFactory的getBean方法会调用AbstractBeanFactory的doGetBean方法
在这里插入图片描述
doGetBean方法调用DefaultSingletonBeanRegistry的getSingleton方法,singletonObjects是一个ConcurrentHashMap对象,用来缓存单例对象,key是Bean的名称,value是Bean实例。从缓存对象中根据名称获取到的是一个JDK动态代理对象。那这个代理对象是什么时候放入缓存中的呢?

/** Cache of singleton objects: bean name --> bean instance */
private final Map singletonObjects = new ConcurrentHashMap(256);

Spring源码分析:AOP代理_第1张图片
我们在DefaultSingletonBeanRegistry类中找找this.singletonObjects.put关键字,看看这个对象是什么时候放入缓存的。由下图可以看到,是通过AnnotationConfigApplicationContext的构造方法将代理对象加载到缓存中的。那这个代理对象是怎么生成的呢?Spring是如何判断应该使用JDK动态代理还是Cglib代理呢?
Spring源码分析:AOP代理_第2张图片

生成代理对象

通过DefaultListableBeanFactory的preInstantiateSingletons方法,调用AbstractBeanFactory的getBean方法,再调用doGetBean方法,从缓存中获取不到对应的实例,调用AbstractAutowireCapableBeanFactory的createBean方法,再调用initializeBean方法,再调用applyBeanPostProcessorsAfterInitialization方法,调用AbstractAutoProxyCreator的postProcessAfterInitialization方法,再调用wrapIfNecessary方法,再调用createProxy方法,再调用ProxyFactory的getProxy方法,再调用ProxyCreatorSupport的createAopProxy方法,最后调用DefaultAopProxyFactory的createAopProxy方法,生成JDK代理对象,再放入缓存中。
Spring源码分析:AOP代理_第3张图片
判断是否使用Cglib代理有三个条件:
(1)ProxyConfig的optimize值是否是true,默认值是false;
(2)proxyTargetClass参数的值是否是true,默认值是false;可以修改@EnableAspectJAutoProxy注解的proxyTargetClass值;
(3)是否实现了接口,没有实现接口就用Cglib代理。
Spring源码分析:AOP代理_第4张图片
执行过程如下:
Spring源码分析:AOP代理_第5张图片

为什么JDK动态代理必须是接口

byte[] $Proxies = ProxyGenerator.generateProxyClass("$Proxy", new Class[]{ITestService.class});
FileOutputStream fileOutputStream = new FileOutputStream("D:\\Test.class");
fileOutputStream.write($Proxies);
fileOutputStream.flush();
fileOutputStream.close();

输出Test.class,复制到IDEA查看。
Java的特性是单继承多实现,生成的代理类已经继承了Proxy类,所以只能实现接口了。Spring源码分析:AOP代理_第6张图片

你可能感兴趣的:(Spring,spring,源码)