AspectJProxyFactory
其实ProxyFactory拥有的功能AspectjProxyFactory都有,它可以使用编程的方式去创建代理
在低版本Spring中定义一个切面是比较麻烦的,需要实现特定的接口,并进行一些较为复杂的配置,低版本Spring AOP的配置是被批评最多的地方。Spring听取这方面的批评声音,并下决心彻底改变这一现状。在Spring2.0中,Spring AOP已经焕然一新,你可以使用@AspectJ注解非常容易的定义一个切面,不需要实现任何的接口
AspectJ是目前大家最常用的 起到集成AspectJ和Spring,也就是我们平时长谈的:自动代理模式。它整个代理的过程全部交给Spring内部去完成,无侵入。
我们只需要配置切面、通知、切点表达式就能自动的实现切入的效果,使用起来极其方便,对调用者可以说是非常透明化的。相信这也是为何当下最流行这种方式的原因~
Demo体验
@Aspect class MyAspect { @Pointcut("execution(* hello(..))") private void beforeAdd() { } @Before("beforeAdd()") public void before1() { System.out.println("-----------before-----------"); } }
在上述切面类定义中我们定义了一个Advisor(采用注解@Aspect标注的),其对应了一个MethodBeforeAdvice,实际上是一个AspectJMethodBeforeAdvice,该Advice对应的是上面的before1()方法,还对应了一个Pointcut:是一个AspectJExpressionPointcut。
该Advisor的语义拦截所有的方法名为**“hello”**的方法在它之前执行MyAspect.before1()方法。
如果我们现在需要创建一个代理对象,其需要绑定的Advisor逻辑跟上面定义的切面类中定义的Advisor类似。则我们可以进行如下编程:
public static void main(String[] args) { AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new HelloServiceImpl()); // 注意:此处得MyAspect类上面的@Aspect注解必不可少 proxyFactory.addAspect(MyAspect.class); //proxyFactory.setProxyTargetClass(true);//是否需要使用CGLIB代理 HelloService proxy = proxyFactory.getProxy(); proxy.hello(); System.out.println(proxy.getClass()); //class com.sun.proxy.$Proxy6 } 输出: -----------before----------- this is my method~~ class com.sun.proxy.$Proxy6
这里面很有意思的地方在于:我们只是proxyFactory.addAspect(MyAspect.class);
,就自动帮我们完成了方法、通知的绑定工作。
原理
public class AspectJProxyFactory extends ProxyCreatorSupport { /** Cache for singleton aspect instances */ private static final Map<Class<?>, Object> aspectCache = new ConcurrentHashMap<>(); //基于AspectJ时,创建Spring AOP的Advice 下面详说 private final AspectJAdvisorFactory aspectFactory = new ReflectiveAspectJAdvisorFactory(); public AspectJProxyFactory() { } public AspectJProxyFactory(Object target) { Assert.notNull(target, "Target object must not be null"); setInterfaces(ClassUtils.getAllInterfaces(target)); setTarget(target); } public AspectJProxyFactory(Class<?>... interfaces) { setInterfaces(interfaces); } // 这两个addAspect方法是最重要的:我们可以把一个现有的aspectInstance传进去,当然也可以是一个Class(下面)====== public void addAspect(Object aspectInstance) { Class<?> aspectClass = aspectInstance.getClass(); String aspectName = aspectClass.getName(); AspectMetadata am = createAspectMetadata(aspectClass, aspectName); // 显然这种直接传实例进来的,默认就是单例的。不是单例我们就报错了~~~~ if (am.getAjType().getPerClause().getKind() != PerClauseKind.SINGLETON) { throw new IllegalArgumentException( "Aspect class [" + aspectClass.getName() + "] does not define a singleton aspect"); } // 这个方法就非常的关键了~~~ Singleton...是它MetadataAwareAspectInstanceFactory的子类 addAdvisorsFromAspectInstanceFactory( new SingletonMetadataAwareAspectInstanceFactory(aspectInstance, aspectName)); } public void addAspect(Class<?> aspectClass) { String aspectName = aspectClass.getName(); AspectMetadata am = createAspectMetadata(aspectClass, aspectName); MetadataAwareAspectInstanceFactory instanceFactory = createAspectInstanceFactory(am, aspectClass, aspectName); addAdvisorsFromAspectInstanceFactory(instanceFactory); } // 从切面工厂里,把对应切面实例里面的增强器(通知)都获取到~~~ private void addAdvisorsFromAspectInstanceFactory(MetadataAwareAspectInstanceFactory instanceFactory) { // 从切面工厂里,先拿到所有的增强器们~~~ List<Advisor> advisors = this.aspectFactory.getAdvisors(instanceFactory); Class<?> targetClass = getTargetClass(); Assert.state(targetClass != null, "Unresolvable target class"); advisors = AopUtils.findAdvisorsThatCanApply(advisors, targetClass); AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(advisors); AnnotationAwareOrderComparator.sort(advisors); addAdvisors(advisors); } }
注意:
- 需要注意的是在使用AspectjProxyFactory基于切面类创建代理对象时,我们指定的切面类上必须包含@Aspect注解。
- 虽然我们自己通过编程的方式可以通过AspectjProxyFactory创建基于@Aspect标注的切面类的代理,但是通过配置<aop:aspectj-autoproxy/>(@EnableAspectJAutoProxy)使用基于注解的Aspectj风格的Aop时,Spring内部不是通过AspectjProxyFactory创建的代理对象,而是通过ProxyFactory(这个在分析自动代理源码的时候有说到过~~~~)
总结
这三个类本身没有什么关系,但都继承自:ProxyCreatorSupport,创建代理对象的核心逻辑都是在ProxyCreatorSupport中实现的
AspectJProxyFactory,ProxyFactoryBean,ProxyFactory 大体逻辑都是:
1.填充AdvisedSupport(ProxyCreatorSupport是其子类)的,然后交给父类ProxyCreatorSupport。
2.得到JDK或者CGLIB的AopProxy
3.代理调用时候被invoke或者intercept方法拦截 (分别在JdkDynamicAopProxy和ObjenesisCglibAopProxy(CglibAopProxy的子类)的中)
并且在这两个方法中调用ProxyCreatorSupport的getInterceptorsAndDynamicInterceptionAdvice方法去初始化advice和各个方法直接映射关系并缓存