Spring AOP实现浅析 二

97 阅读3分钟

紧接上文《Spring AOP实现浅析 一》,本文继续介绍了Spring AOP实现的基础知识,了解了这些,将一步步带你明白Spring AOP实现的由来和历程。

一 BeanNameAutoProxyCreator类

使用ProxyFactoryBean,虽然可以将代理对象作为bean放入Spring容器中,但是还得我们手动指定被代理类对象,而且只能一个个类去创建代理对象。

有更高级、更方便的实现吗?那就是BeanNameAutoProxyCreator。

来看示例:定义被代理类OrderService、代理逻辑SimpleAroundAdvise。

import org.springframework.stereotype.Component;

@Component
public class OrderService implements OrderInterface {

    public void test() {
        System.out.println("执行OrderService.test");
    }
}
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.stereotype.Component;

@Component
public class SimpleAroundAdvise implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("SimpleAroundAdvise before...");
        Object proceed = invocation.proceed();
        System.out.println("SimpleAroundAdvise after...");
        return proceed;
    }
}

对容器中beanName以orderSer开头的bean对象,都创建代理对象,应用simpleAroundAdvise通知。

import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;

@Component
@ComponentScan(value = "com.xiakexing")
public class AppConfig {

    @Bean
    public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
		BeanNameAutoProxyCreator proxyCreator = new BeanNameAutoProxyCreator();
		proxyCreator.setBeanNames("orderSer*");
		proxyCreator.setInterceptorNames("simpleAroundAdvise");
		proxyCreator.setProxyTargetClass(true);
		return proxyCreator;
    }
}
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
OrderService orderService = context.getBean("orderService", OrderService.class);
orderService.test();

不足之处是只能根据beanName指定被代理类,将对类中所有方法都进行增强,而不能指定某些方法。

现在,是不是有了一点自动化的味道。

二 DefaultAdvisorAutoProxyCreator类

DefaultAdvisorAutoProxyCreator能根据容器中所有Advisor类型的Bean,判断哪些Bean需要被代理,并创建代理对象。

import com.xiakexing.aop.SimpleBeforeAdvice;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.NameMatchMethodPointcut;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;

@Component
@ComponentScan(value = "com.xiakexing")
public class AppConfig {

    @Bean
    public DefaultPointcutAdvisor defaultPointcutAdvisor() {
        NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
        // 指定要代理的类
        pointcut.setClassFilter(new ClassFilter() {
            @Override
            public boolean matches(Class<?> clazz) {
                return clazz.getName().startsWith("com.xiakexing.service.Order");
            }
        });
        // 指定要代理的方法
        pointcut.addMethodName("test");
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setPointcut(pointcut);
        // 通知
        advisor.setAdvice(new SimpleBeforeAdvice());
        return advisor;
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        return new DefaultAdvisorAutoProxyCreator();
    }
}
public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    UserService userService = context.getBean("userService", UserService.class);
    userService.test();
    OrderInterface orderService = context.getBean("orderService", OrderInterface.class);
    orderService.test();
}

userService.test()并未被增加,而orderService.test()被代理了。 此时,创建Pointcut是不是更灵活了?

到此,能否更进一步,让创建Advisor更简单呢?那就是使用注解,如@Before、@After等, Spring会将 execution表达式封装为Pointcut,将所注释的方法封装为Advice。

三 再看Advice

创建ProxyFactory对象时,调用addAdvice(Advice advice)来设置通知,将保存到父类AdvisedSupport#advisors集合中。

Spring中,Advice本身是个空接口,有多个细分的子接口,分别对应5个注解。

  1. MethodBeforeAdvice接口,对应@Before,实现类AspectJMethodBeforeAdvice
  2. AfterReturningAdvice接口,@AfterReturning,实现类AspectJAfterReturningAdvice
  3. ThrowsAdvice接口,对应@AfterThrowing,实现类AspectJAfterThrowingAdvice
  4. AfterAdvice接口,对应@After,实现类AspectJAfterAdvice
  5. MethodInterceptor接口,对应@Around,实现类AspectJAroundAdvice

来看一个示例:定义UserService、SimpleBeforeAdvice类

public class UserService {
    public void test() {
        System.out.println("执行UserService.test");
    }
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;

public class SimpleBeforeAdvice implements MethodBeforeAdvice {

    // 只定义代理逻辑,不用手动回调
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("MethodBeforeAdvice...");
    }
}
public static void main(String[] args) {
    UserService target = new UserService();
    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.setTarget(target);
    // 添加通知
    proxyFactory.addAdvice(new SimpleBeforeAdvice());
    UserService userService = (UserService) proxyFactory.getProxy();
    System.out.println(userService.getClass().getName());
    userService.test();
}

看到这儿,是不是有点熟悉了?

当类中某个方法使用@Before时,Spring中就是将它封装为BeforeAdvice接口实现。其他注解类似。

四 猜测Spring AOP实现

有了上面的背景知识,想想Spring AOP的使用方式,我们来猜测它的实现细节:

  1. 当在配置类上使用@EnableAspectJAutoProxy时,应该会向容器中注册某个类,这个类会将带有@Aspect的类解析,将@Before等注解解析为Pointcut对象,将方法解析为Advice对象,组装为Advisor对象放入容器中;
  2. 在bean的初始化后阶段,如果某个bean符合任意Advisor的Pointcut限制,则通过ProxyFactory为这个bean创建代理对象proxy,并将proxy放入Spring容器,而proxy的target对象就是当前bean;
  3. 解析注解获得Advisor、创建代理对象,这些步骤应该是由一个类似DefaultAdvisorAutoProxyCreator的类来实现。

在下一篇博文中,将深入源码,来看看Spring AOP的底层细节。