紧接上文《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个注解。
- MethodBeforeAdvice接口,对应@Before,实现类AspectJMethodBeforeAdvice
- AfterReturningAdvice接口,@AfterReturning,实现类AspectJAfterReturningAdvice
- ThrowsAdvice接口,对应@AfterThrowing,实现类AspectJAfterThrowingAdvice
- AfterAdvice接口,对应@After,实现类AspectJAfterAdvice
- 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的使用方式,我们来猜测它的实现细节:
- 当在配置类上使用@EnableAspectJAutoProxy时,应该会向容器中注册某个类,这个类会将带有@Aspect的类解析,将@Before等注解解析为Pointcut对象,将方法解析为Advice对象,组装为Advisor对象放入容器中;
- 在bean的初始化后阶段,如果某个bean符合任意Advisor的Pointcut限制,则通过ProxyFactory为这个bean创建代理对象proxy,并将proxy放入Spring容器,而proxy的target对象就是当前bean;
- 解析注解获得Advisor、创建代理对象,这些步骤应该是由一个类似DefaultAdvisorAutoProxyCreator的类来实现。
在下一篇博文中,将深入源码,来看看Spring AOP的底层细节。