Spring框架进阶Spring V2.0 AOP
Posted 烟锁迷城
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring框架进阶Spring V2.0 AOP相关的知识,希望对你有一定的参考价值。
1、源码方法
AOP是Spring框架最重要的功能之一,它负责减少代码的冗余,简化开发流程。AOP,就是面向切面,主要使用代理模式进行设计
在Spring中,其实现流程是
- getBean:获取Bean的方法
- ApplicationContext:不必赘述
- AdvisedSupport:完成对配置文件的解析,构建切面与切点的关系
- AopConfig:保存AOP配置信息
- Advice:完成切面方法的回调
- JDKDynamicAopProxy:生成代理类,此为JDK代理,还有CglibAopProxy完成Cglib的代理,Spring同时支持两种方式的代理,因为它们都继承AopProxy,通过DefaultAopProxyFactory的策略模式来进行选择。
2、实现思路
在实例化Bean的时候,查看是否需要进行代理,如果需要,就要将原本的类替换为代理对象,反之返回初始对象。
检测是否需要代理的条件是是否满足代理的过滤要求,需要指定对应的代理。
实际上,在Spring框架中,实际被代理的类是实现类,而非接口。
设置一个类,AopConfig,用来保存这些固定的配置。
public class MyAopConfig
private String pointCut;
private String aspectClass;
private String aspectBefore;
private String aspectAfter;
private String aspectAfterThrow;
private String aspectAfterThrowingName;
public String getPointCut()
return pointCut;
public void setPointCut(String pointCut)
this.pointCut = pointCut;
public String getAspectClass()
return aspectClass;
public void setAspectClass(String aspectClass)
this.aspectClass = aspectClass;
public String getAspectBefore()
return aspectBefore;
public void setAspectBefore(String aspectBefore)
this.aspectBefore = aspectBefore;
public String getAspectAfter()
return aspectAfter;
public void setAspectAfter(String aspectAfter)
this.aspectAfter = aspectAfter;
public String getAspectAfterThrow()
return aspectAfterThrow;
public void setAspectAfterThrow(String aspectAfterThrow)
this.aspectAfterThrow = aspectAfterThrow;
public String getAspectAfterThrowingName()
return aspectAfterThrowingName;
public void setAspectAfterThrowingName(String aspectAfterThrowingName)
this.aspectAfterThrowingName = aspectAfterThrowingName;
里面放置的条件依次为
- 符合匹配条件的类名
- 作为切面功能的类
- 前置方法
- 后置方法
- 抛错方法
- 抛错类型
private MyAdvisedSupport instantiateAopConfig()
MyAopConfig config = new MyAopConfig();
config.setPointCut("public .* com.example.springwrite.demo.service..*ServiceImpl..*(.*)");
config.setAspectClass("com.example.springwrite.demo.aspect.LogAspect");
config.setAspectBefore("aspectBefore");
config.setAspectAfter("aspectAfter");
config.setAspectAfterThrow("aspectAfterThrow");
config.setAspectAfterThrowingName("java.lang.Exception");
return new MyAdvisedSupport(config);
增加类AdvisedSupport,用来保存被代理的类和类实例
public class MyAdvisedSupport
private MyAopConfig config;
//目标Class
private Class targetClass;
//目标对象
private Object target;
public MyAdvisedSupport(MyAopConfig config)
this.config = config;
如果符合代理筛选规则,就进行代理,反之就不需要
代理使用的是策略模式,用来自动选择使用JDK代理还是Cglib代理
private Object instantiateBean(String beanName, MyBeanDefinition beanDefinition)
//如果是单例对象,直接返回在缓存中的对象
if (beanDefinition.isSingleton() && this.factoryBeanObjectCache.containsKey(beanName))
return this.factoryBeanObjectCache.get(beanName);
String beanClassName = beanDefinition.getBeanClassName();
Object instance = null;
try
Class<?> aClass = Class.forName(beanClassName);
instance = aClass.newInstance();
//如果是代理对象,将触发AOP代理
MyAdvisedSupport config = instantiateAopConfig();
config.setTarget(instance);
config.setTargetClass(aClass);
//判断是否需要代理,需要就调用代理工厂生成代理类,然后放入三级缓存
//如果不需要,就返回原生类
if (config.pointCutMatch())
instance = proxyFactory.createAopProxy(config).getProxy();
this.factoryBeanObjectCache.put(beanName, instance);
for (Class<?> anInterface : aClass.getInterfaces())
this.factoryBeanObjectCache.put(anInterface.getName(), instance);
catch (Exception e)
e.printStackTrace();
return instance;
使用默认代理工厂,如果有接口,就使用JDK代理,如果没有就使用Cglib代理
public class MyDefaultAopProxyFactory
public MyAopProxy createAopProxy(MyAdvisedSupport config)
if (config.getTargetClass().getInterfaces().length > 0)
return new MyJdkDynamicAopProxy(config);
return new MyCglibAopProxy(config);
MyCglibAopProxy和MyJdkDynamicAopProxy都继承于MyAopProxy
public interface MyAopProxy
Object getProxy();
Object getProxy(ClassLoader classLoader);
现在实现判断是否需要代理的方法,这里我简化了一下,只过滤指定的包下的类。
public class MyAdvisedSupport
private MyAopConfig config;
private Map<Method, List<MyMethodInterceptor>> methodCache = new HashMap<Method, List<MyMethodInterceptor>>();
private Pattern pointCutClassPattern;
//目标Class
private Class targetClass;
//目标对象
private Object target;
public MyAdvisedSupport(MyAopConfig config)
this.config = config;
public MyAopConfig getConfig()
return config;
public Class getTargetClass()
return targetClass;
public void setTargetClass(Class targetClass)
this.targetClass = targetClass;
public Object getTarget()
return target;
public void setTarget(Object target)
this.target = target;
public boolean pointCutMatch()
boolean matches = this.targetClass.toString().contains("com.example.springwrite.demo.service");
return matches;
在Spring框架中,将方法与代理方法列表的关系保存起来,并且将所有代理切面方法放进这个列表中,形成链条。
private Map<Method, List<MyMethodInterceptor>> methodCache = new HashMap<Method, List<MyMethodInterceptor>>();
List<MyMethodInterceptor>是方法拦截,可以根据目前的代理增强分为三种,前置,后置和错误后置。
基础方法,只有调用增强
public interface MyMethodInterceptor
Object invoke(MyMethodInvocation invocation) throws Throwable;
这个抽象类的目的在于,让三个切面能有公共的调用抽取,就是invokeAdviceMethod
invokeAdviceMethod具有三个参数,切点,返回值和抛出错误,其内部是用反射实现的,反射将调用aspect切面类的advicemethod方法。有没有参数作为调用区分,如果无参,则直接反射调用即可,如果为有参,则需要根据参数类型判断该参数在列表中的位置,放入后完成反射调用
public abstract class MyAbstractAspectJAdvice implements MyAdvice
private Object aspect;
private Method adviceMethod;
private String throwName;
public MyAbstractAspectJAdvice(Object aspect, Method adviceMethod)
this.aspect = aspect;
this.adviceMethod = adviceMethod;
protected Object invokeAdviceMethod(MyJoinPoint joinPoint, Object returnValue, Throwable ex) throws Throwable
Class<?>[] parameterTypes = this.adviceMethod.getParameterTypes();
if (null == parameterTypes || parameterTypes.length == 0)
return this.adviceMethod.invoke(aspect);
else
Object[] args = new Object[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++)
if (parameterTypes[i] == MyJoinPoint.class)
args[i] = joinPoint;
else if (parameterTypes[i] == Throwable.class)
args[i] = ex;
else if (parameterTypes[i] == Object.class)
args[i] = returnValue;
return this.adviceMethod.invoke(aspect, args);
切点接口包含一些参数,包括代理的类,参数列表,代理的方法,存放键值对的UserAttribute方法
public interface MyJoinPoint
Object getThis();
Object[] getArguments();
Method getMethod();
void setUserAttribute(String key, Object value);
Object getUserAttribute(String key);
其对应的实现为MethodInvocation,这里面实现了关键的proceed方法,用来实现代理的反复调用。
如果代理链条List<MyMethodInterceptor> chain是空的,就代表没有任何代理,直接调用本来的方法即可。
如果不为空,就从第一个开始进行匹配,如果匹配结果是MethodInterceptor的继承类,就执行代理,反之就进行递归调用。
但是可以发现的是,这里的方法并不区分前置,后置和抛错,那么AOP是如何确保执行顺序的呢?
public class MyMethodInvocation implements MyJoinPoint
protected final Object proxy;
protected final Object target;
protected final Method method;
protected Object[] arguments = new Object[0];
private final Class<?> targetClass;
private Map<String, Object> userAttributes = new HashMap<String, Object>();
protected final List<?> interceptorsAndDynamicMethodMatchers;
private Map<String, Object> userAttribute = new HashMap<String, Object>();
private int currentInterceptorIndex = -1;
public MyMethodInvocation(Object proxy, Object target, Method method, Object[] args, Class targetClass, List<MyMethodInterceptor> chain)
this.proxy = proxy;
this.target = target;
this.method = method;
this.arguments = args;
this.targetClass = targetClass;
this.interceptorsAndDynamicMethodMatchers = chain;
public Object proceed() throws Throwable
//如果代理链条是空的,就证明没有被代理,直接执行方法本身
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1)
return this.method.invoke(target, this.arguments);
Object interceptorsAndDynamic = this.interceptorsAndDynamicMethodMatchers.get(++currentInterceptorIndex);
//如果符合匹配要求,就执行对应代理
if (interceptorsAndDynamic instanceof MyMethodInterceptor)
MyMethodInterceptor mi = (MyMethodInterceptor) interceptorsAndDynamic;
return mi.invoke(this);
else
//否则递归调用
return proceed();
public Method getMethod()
return this.method;
@Override
public void setUserAttribute(String key, Object value)
this.userAttribute.put(key, value);
@Override
public Object getUserAttribute(String key)
return this.userAttribute.get(key);
public Object[] getArguments()
return this.arguments;
public Object getThis()
return this.target;
在MethodBeforeAdviceInterceptor类中,可以看到,是先执行前置增强,再进行递归调用
public class MyMethodBeforeAdviceInterceptor extends MyAbstractAspectJAdvice implements MyMethodInterceptor
private MyJoinPoint joinPoint;
public MyMethodBeforeAdviceInterceptor(Object newInstance, Method method)
super(newInstance, method);
@Override
public Object invoke(MyMethodInvocation mi) throws Throwable
joinPoint = mi;
this.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
private void before(Object method, Object arguments, Object aThis) throws Throwable
invokeAdviceMethod(joinPoint, null, null);
在MyMethodAfterReturningAdviceInterceptor中,先执行递归调用,再进行增强方法调用
public class MyMethodAfterReturningAdviceInterceptor extends MyAbstractAspectJAdvice implements MyMethodInterceptor
private MyJoinPoint joinPoint;
public MyMethodAfterReturningAdviceInterceptor(Object newInstance, Method method)
super(newInstance, method);
@Override
public Object invoke(MyMethodInvocation mi) throws Throwable
joinPoint = mi;
Object proceed = mi.proceed();
this.after(proceed, mi.getMethod(), mi.getArguments(), mi.getThis());
return proceed;
private void after(Object proceed, Method method, Object[] arguments, Object aThis) throws Throwable
this.invokeAdviceMethod(joinPoint, proceed, null);
在MyAspectAfterThrowingAdvice 中,只有抛出错误,才会执行
public class MyAspectAfterThrowingAdvice extends MyAbstractAspectJAdvice implements MyMethodInterceptor
private String throwingName;
public MyAspectAfterThrowingAdvice(Object newInstance, Method method)
super(newInstance, method);
@Override
public Object invoke(MyMethodInvocation mi) throws Throwable
try
return mi.proceed();
catch (Throwable ex)
this.invokeAdviceMethod(mi, null, ex);
throw ex;
public void setThrowName(String aspectAfterThrowingName)
this.throwingName = aspectAfterThrowingName;
这样通过递归调用和增强调用的顺序更换,就保证了增强顺序的执行不会有错误。
那么接下来就是将代理方法装载到对应的代理链条中
这个方法就是通过获取到被代理类的全部方法,将这些方法和代理增强方法进行绑定。
private void parse()
//修饰符 返回值 包名 类名 方法名(参数列表)
String pointCut = config.getPointCut()
.replaceAll("\\\\.", "\\\\\\\\.")
.replaceAll("\\\\\\\\.\\\\*", ".*")
.replaceAll("\\\\(", "\\\\\\\\(")
.replaceAll("\\\\)", "\\\\\\\\)");
methodCache = new HashMap<Method, List<MyMethodInterceptor>>();
Map<String, Method> aspectMethods = new HashMap<String, Method>();
try
Class aspectClass = Class.forName(this.config.getAspectClass());
for (Method method : aspectClass.getMethods())
aspectMethods.put(method.getName(), method);
for (Method method : this.targetClass.getMethods())
String methodString = method.toString();
if (methodString.contains("throw"))
methodString = methodString.substring(0, methodString.lastIndexOf("throws")).trim();
Matcher matcher = Pattern.compile(pointCut).matcher(methodString);
if (matcher.matches())
List<MyMethodInterceptor> advices = new LinkedList<MyMethodInterceptor>();
if (null != this.config.getAspectBefore() && !"".equals(this.config.getAspectBefore()))
advices.add(new MyMethodBeforeAdviceInterceptor(aspectClass.newInstance(), aspectMethods.get(this.config.getAspectBefore())));
if (null != this.config.getAspectAfter() && !"".equals(this.config.getAspectAfter()))
advices.add(new MyMethodAfterReturningAdviceInterceptor(aspectClass.newInstance(), aspectMethods.get(this.config.getAspectAfter())));
if (null != this.config.getAspectAfterThrow() && !"".equals(this.config.getAspectAfterThrow()))
MyAspectAfterThrowingAdvice myAspectAfterThrowingAdvice = new MyAspectAfterThrowingAdvice(aspectClass.newInstance(), aspectMethods.get(this.config.getAspectAfterThrow()));
myAspectAfterThrowingAdvice.setThrowName(this.config.getAspectAfterThrowingName());
advices.add(myAspectAfterThrowingAdvice);
this.methodCache.put(method, advices);
catch (Exception e)
e.printStackTrace();
绑定完毕,就需要进行调用了,调用时通过JDK代理进行,即JDKDynamicAopProxy,继承InvocationHandler 之后,重写invoke方法,在这里获取到对应的代理链条等数据。
在这里有一个方法,getInterceptorsAndDynamicInterceptionAdvice是用来获取代理链条的,但是直接从绑定关系中获取不就可以了,为什么还要一个单独的方法?
public class MyJdkDynamicAopProxy implements MyAopProxy, InvocationHandler
private MyAdvisedSupport advised;
public MyJdkDynamicAopProxy(MyAdvisedSupport advised)
this.advised = advised;
@Override
public Object getProxy()
return getProxy(this.getClass().getClassLoader());
@Override
public Object getProxy(ClassLoader classLoader)
return Proxy.newProxyInstance(classLoader, this.advised.getTargetClass().getInterfaces(), this);
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
List<MyMethodInterceptor> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, this.advised.getTargetClass());
MyMethodInvocation mi = new MyMethodInvocation(proxy, this.advised.getTarget(), method, args, this.advised.getTargetClass(), chain);
return mi.proceed();
因为方法是有可能没有获取到的,也许是因为接口继承等缘故,所以需要根据方法名和参数名到被代理类中重新寻找锁定,将正确的结果重新绑定并返回,是一个保险作用。
public List<MyMethodInterceptor> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass)
List<MyMethodInterceptor> stringMyAdviceMap = this.methodCache.get(method);
if (null == stringMyAdviceMap)
Method m = null;
try
m = targetClass.getMethod(method.getName(), method.getParameterTypes());
catch (NoSuchMethodException e)
e.printStackTrace();
stringMyAdviceMap = methodCache.get(m);
methodCache.put(method, stringMyAdviceMap);
return stringMyAdviceMap;
3、最终总结
AOP代理的本质是调用代理模式,从实例化Bean开始切入,借助三级缓存来进行实现,获取对应的切面配置,用AdviceSupport完成代理方法和切点链条的匹配,用MethodInvocation保存切点信息,用策略来选择使用JdkDynamicAopProxy还是MyCglibAopProxy,因为这两个都继承了AopProxy类,用MethodInterecptor进行拦截,Adice进行切点回调,通过递归调用proceed方法来实现代理,并且通过调整增强方法和proceed方法的顺序来保证前置后置等切面方法的顺序执行,是非常精妙的设计
以上是关于Spring框架进阶Spring V2.0 AOP的主要内容,如果未能解决你的问题,请参考以下文章