前言
上一篇文章讲了如何自定义IOC。这篇讲一下Spring的AOP过程,介绍一下Spring对Advisor的加载和使用,并通过自定义Aspect和Advisor,实现简单的Aop功能。
Spring Aop
Spring开启AOP一般是使用@EnableAspectJAutoProxy来开启的。这个注解的主要作用是注入了一个实现了BeanPostProcessor接口的类。这个接口在前面介绍过,会嵌入到Bean的实例化过程。
所以只要我们注入这个类AnnotationAwareAspectJAutoProxyCreator也可以开启AOP功能了。完整的代码放在Github上。
@Bean
public AnnotationAwareAspectJAutoProxyCreator makeAnnotationAwareAspectJAutoProxyCreator() {
return new AnnotationAwareAspectJAutoProxyCreator();
}
调试AnnotationAwareAspectJAutoProxyCreator的源码会发现,这个类继承的AbstractAutoProxyCreator的方法postProcessAfterInitialization中对符合切片的bean进行了二次代理,具体的代码如下。
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.containsKey(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.containsKey(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
Aspect是通过BeanFactoryAspectJAdvisorsBuilder的buildAspectJAdvisors方法加载的。这个方法会读取bean的切片信息,并生成Advisor的列表,同时存在advisorsCache里面。
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = null;
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new LinkedList<Advisor>();
aspectNames = new LinkedList<String>();
String[] beanNames =
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this
// case they would be cached by the Spring container but would not
// have been weaved
Class beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
if (aspectNames.isEmpty()) {
return Collections.EMPTY_LIST;
}
List<Advisor> advisors = new LinkedList<Advisor>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
使用的时候,Spring会根据pointCut选择合适的Advisor对相应的Bean做代理。
protected List<Advisor> findEligibleAdvisors(Class beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
二次代理的Bean在执行的过程中是使用ReflectiveMethodInvocation的proceed方法来执行Advisor的处理逻辑的。
上一步选出来的Advisor存在interceptorsAndDynamicMethodMatchers属性里,这是一个Advisor的列表,所以执行的过程中采用了责任链模式,不同的Advisor会依次调用下一个Advisor。
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
这条责任链里包含了Advisor的处理顺序,通过程序的流程图能能明显的表示出来,为了完整描述,这里假设是完整的Advisor。
从图中可以完整的看出来各个Advisor的执行顺序。
自定义AOP
所以自定义AOP也是相同的思路,通过继承BeanPostProcessor来二次代理bean,完整的代码放在Github上了。
为了简便起见,只定义了一个注解@MyAspect,具体的Advisor通过函数名控制。
先看注解的定义,加上Component使Spring可以识别这个注解,并加载,pointCut属性则是定义切片。
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface MyAspect {
String value() default "";
String pointCut();
}
再看具体的使用上,pointCut定义了切片,然后定义了before,after,around,这三个方法,目前只实现了这三个具有代表性的Advisor。
@Configuration
public class CustomizeAspectTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.register(CustomizeAspectTest.class);
annotationConfigApplicationContext.refresh();
Test test = annotationConfigApplicationContext.getBean(Test.class);
test.test();
}
@Component
public static class Test {
public void test() {
System.out.println("hello world");
}
}
@MyAspect(pointCut = "org.wcong.test.spring.aop.CustomizeAspectTest.Test.test")
public static class MyAspectClass {
void before(Object[] args) {
System.out.println("aop before");
}
void after(Object[] args) {
System.out.println("aop after");
}
void around(MethodInvocation methodInvocation, Object[] args) throws Throwable {
System.out.println("aop around before");
methodInvocation.proceed(methodInvocation);
System.out.println("aop around after");
}
}
@Bean
public CustomizeAspectProxy getCustomizeAspectScan() {
return new CustomizeAspectProxy();
}
}
可以发现最后导出了一个CustomizeAspectProxy的类,这个就是自定义Aop的切入点了。这里面主要实现了Advisor的加载,和对符合切片的Bean的二次代理。
public class CustomizeAspectProxy implements BeanPostProcessor, ApplicationContextAware {
private ApplicationContext applicationContext;
private List<AbstractAdvisor> advisorList;
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
buildAdvisor();
Map<Method, List<AbstractAdvisor>> matchAdvisorMap = matchAdvisor(bean);
if (matchAdvisorMap.isEmpty()) {
return bean;
} else {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(bean.getClass());
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setCallback(new MethodInterceptorImpl(matchAdvisorMap));
return enhancer.create();
}
}
private Map<Method, List<AbstractAdvisor>> matchAdvisor(Object bean) {
Class<?> beanClass = bean.getClass();
Method[] methods = beanClass.getMethods();
if (methods == null) {
return Collections.emptyMap();
}
Map<Method, List<AbstractAdvisor>> methodListMap = new HashMap<Method, List<AbstractAdvisor>>();
for (Method method : methods) {
for (AbstractAdvisor abstractAdvisor : advisorList) {
if (!abstractAdvisor.isMatch(bean.getClass(), method)) {
continue;
}
List<AbstractAdvisor> advisorList = methodListMap.get(method);
if (advisorList == null) {
advisorList = new LinkedList<AbstractAdvisor>();
methodListMap.put(method, advisorList);
}
advisorList.add(abstractAdvisor);
}
}
return methodListMap;
}
private void buildAdvisor() {
if (advisorList != null) {
return;
}
synchronized (this) {
if (advisorList != null) {
return;
}
String[] beanNames = applicationContext.getBeanDefinitionNames();
advisorList = new ArrayList<AbstractAdvisor>();
for (String beanName : beanNames) {
Class<?> beanClass = applicationContext.getType(beanName);
MyAspect myAspect = beanClass.getAnnotation(MyAspect.class);
if (myAspect == null) {
continue;
}
Method[] methods = beanClass.getDeclaredMethods();
if (methods == null) {
continue;
}
Object bean = applicationContext.getBean(beanName);
List<AbstractAdvisor> beanAdvisorList = new ArrayList<AbstractAdvisor>(methods.length);
for (Method method : methods) {
if (method.getName().equals("before")) {
beanAdvisorList.add(new MethodInvocation.BeforeAdvisor(bean, method));
} else if (method.getName().equals("around")) {
beanAdvisorList.add(new MethodInvocation.AroundAdvisor(bean, method));
} else if (method.getName().equals("after")) {
beanAdvisorList.add(new MethodInvocation.AfterAdvisor(bean, method));
}
}
advisorList.addAll(beanAdvisorList);
}
Collections.sort(advisorList, new Comparator<AbstractAdvisor>() {
public int compare(AbstractAdvisor o1, AbstractAdvisor o2) {
return o1.getOrder() - o2.getOrder();
}
});
}
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
其中buildAdvisor是从applicationContext里面取出所有的bean选出有MyAspect注解的类,解析成Advisor,注意到后面有一个排序,是因为这个责任链是有顺序的,after>around>before。
matchAdvisor则是读取类的信息,判断需要被代理,然后返回每个方法被代理的advisorList。
接下来是实现代理的类了,这个类是cglib的一个简单的判断,发现相应的函数有Advisor,走Aop模式,没有,走普通的代理模式。
public class MethodInterceptorImpl implements MethodInterceptor {
private Map<Method, List<AbstractAdvisor>> advisorMap;
public MethodInterceptorImpl(Map<Method, List<AbstractAdvisor>> advisorMap) {
this.advisorMap = advisorMap;
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
List<AbstractAdvisor> advisorList = advisorMap.get(method);
if (advisorList == null) {
return methodProxy.invokeSuper(o, objects);
} else {
MethodInvocation methodInvocation = new MethodInvocation(o, method, objects, methodProxy, advisorList);
return methodInvocation.proceed(methodInvocation);
}
}
}
MethodInvocation就是具体的责任链实现的Advisor的逻辑了。MethodInvocation包含了具体需要代理的方法的元数据,并在proceed方法中开启方法的执行链路,依次调用。而这条责任链的处理链路就是after->around->before->methodProxy->around->after。
public interface Proceed {
Object proceed(MethodInvocation methodInvocation) throws Throwable;
}
public class MethodInvocation implements Proceed {
private List<AbstractAdvisor> advisorList;
private Object sourceObject;
private Method sourceMethod;
private Object[] sourceParameters;
private MethodProxy sourceMethodProxy;
private int advisorIndex = -1;
public MethodInvocation(Object o, Method method, Object[] objects, MethodProxy methodProxy,
List<AbstractAdvisor> advisorList) {
this.sourceObject = o;
this.sourceMethod = method;
this.sourceParameters = objects;
this.sourceMethodProxy = methodProxy;
this.advisorList = advisorList;
}
public Object proceed(MethodInvocation methodInvocation) throws Throwable {
if (advisorIndex == advisorList.size() - 1) {
return sourceMethodProxy.invokeSuper(sourceObject, sourceParameters);
} else {
advisorIndex += 1;
return advisorList.get(advisorIndex).proceed(this);
}
}
public static class AroundAdvisor extends AbstractAdvisor {
public AroundAdvisor(Object aspectObject, Method aspectMethod) {
super(aspectObject, aspectMethod);
order = AbstractAdvisor.AROUND_ORDER;
}
public Object proceed(MethodInvocation methodInvocation) throws Throwable {
Object[] param = { methodInvocation, methodInvocation.sourceParameters };
return aspectMethod.invoke(aspectObject, param);
}
}
public static class BeforeAdvisor extends AbstractAdvisor {
public BeforeAdvisor(Object aspectObject, Method aspectMethod) {
super(aspectObject, aspectMethod);
order = AbstractAdvisor.BEFORE_ORDER;
}
public Object proceed(MethodInvocation methodInvocation) throws Throwable {
Object[] param = { methodInvocation.sourceParameters };
aspectMethod.invoke(aspectObject, param);
return methodInvocation.proceed(methodInvocation);
}
}
public static class AfterAdvisor extends AbstractAdvisor {
public AfterAdvisor(Object aspectObject, Method aspectMethod) {
super(aspectObject, aspectMethod);
order = AbstractAdvisor.AFTER_ORDER;
}
public Object proceed(MethodInvocation methodInvocation) throws Throwable {
methodInvocation.proceed(methodInvocation);
Object[] param = { methodInvocation.sourceParameters };
return aspectMethod.invoke(aspectObject, param);
}
}
}
结语
Spring Aop的实现主要是bean的二次代理,还是用到了BeanPostProcessor,来嵌入实现的。同时依赖了Aspectj的相关定义,通过Advisor的责任链来实现嵌入到bean方法的执行前后。同时也跟Aspectj高度耦合,会直接使用Aspectj的很多类,就很难实现定制化了。