1.简介
2.如何实现
3.源码分析
(1)找入口
(2)ProxyFactory类的getProxy
(3)JdkDynamicAopProxy类的getProxy(ClassLoader classLoader)
(4)JdkDynamicAopProxy类的invoke方法
(5)Advised.getInterceptorsAndDynamicInterceptionAdvice()
(6)getInterceptorsAndDynamicInterceptionAdvice()
(7)chain
(8)proceed()
4.总结
5.简单实现源码
通知(Advice)的类型
前置通知(Before advice):在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。
后置通知(After advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)
返回后通知(After return advice):在某连接点正常完成后执行的通知,不包括抛出异常的情況。
环绕通知(around advice):包围一个连接点的通知,类似Web中的Filter
抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知
2.如何实现
有两种方式
a)配置
1<aop:aspectj-autoproxy proxy-target-class="true"/>
2
3<bean id="logAspect" class="com.gupaoedu.vip.aop.aspect.LogAspect">bean>
4
5<aop:config>
6 <aop:aspect ref="logAspect">
7 <aop:pointcut expression="execution(* com.gupaoedu.vip.aop.service..*(..))" id="logPointcut"/>
8 <aop:before method="before" pointcut-ref="logPointcut"/>
9 <aop:after-returning method="afterReturn" returning="boolean" pointcut-ref="logPointcut"/>
10 <aop:after method="after" pointcut-ref="logPointcut"/>
11 <aop:after-throwing method="afterThrow" pointcut-ref="logPointcut"/>
12 aop:aspect>
13aop:config>
b)注解
1class="true"/>
2
3public class LogAspect {
4 private final static Logger LOG = Logger.getLogger(LogAspect.class);
5 //声明切点
6 //因为要利用反射机制去读取这个切面中的所有的注解信息
7 @Pointcut("execution(* com.gupaoedu.vip.aop.service..*(..))")
8 public void pointcutConfig(){}
9
10 @Before("pointcutConfig()")
11 public void before(JoinPoint joinPoint){
12 LOG.info("调用方法之前执行" + joinPoint);
13 }
14 @After("pointcutConfig()")
15 public void after(JoinPoint joinPoint){
16 LOG.info("调用之后执行" + joinPoint);
17 }
18 @AfterReturning(returning="returnValue",value="pointcutConfig()")
19 public void afterReturn(JoinPoint joinPoint,Object returnValue){
20 LOG.info("调用获得返回值" + returnValue);
21 }
22 @AfterThrowing("pointcutConfig()")
23 public void afterThrow(JoinPoint joinPoint){
24 LOG.info("抛出异常之后执行" + joinPoint);
25 }
26}
c)表达式解析
3.源码分析
(1)找入口(2)ProxyFactory类的getProxy
通过查找我们找到了ProxyFactory类的getProxy方法,并且我们知道代理的实现方式有两种:JDK与CGLIB
1public Object getProxy() {
2//createAopProxy() 这里面对代理的方式进行了选择,如果代理类实现了接口则用JDK代理,否则使用CGLIB
3 return createAopProxy().getProxy();
4}
(3)JdkDynamicAopProxy类的getProxy(ClassLoader classLoader)
继续跟踪getProxy()方法我们可以得到JdkDynamicAopProxy类的getProxy(ClassLoader classLoader)
1/**
2 *
3 * - 获取代理类要实现的接口,除了Advised对象中配置的,还会加上SpringProxy, Advised(opaque=false)
4 *
- 检查上面得到的接口中有没有定义 equals或者hashcode的接口
5 *
- 调用Proxy.newProxyInstance创建代理对象
6 *
7 */
8 public Object getProxy(ClassLoader classLoader) {
9 if (logger.isDebugEnabled()) {
10 logger.debug("Creating JDK dynamic proxy: target source is " +this.advised.getTargetSource());
11 }
12 Class[] proxiedInterfaces =AopProxyUtils.completeProxiedInterfaces(this.advised);
13 findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
14 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
15}
该方法的目的就是为了获取代理对象,代理对象获得之后,怎么织入切面呢?
(4)JdkDynamicAopProxy类的invoke方法
由代理的实现原理我们知道,代理会实现InvocationHandler接口,那么我们分析一下JdkDynamicAopProxy类的invoke方法
1publicObject invoke(Object proxy, Method method, Object[] args) throwsThrowable {
2 MethodInvocation invocation = null;
3 Object oldProxy = null;
4 boolean setProxyContext = false;
5
6 TargetSource targetSource = this.advised.targetSource;
7 Class targetClass = null;
8 Object target = null;
9
10 try {
11 //eqauls()方法,具目标对象未实现此方法
12 if (!this.equalsDefined && AopUtils.isEqualsMethod(method)){
13 return (equals(args[0])? Boolean.TRUE : Boolean.FALSE);
14 }
15
16 //hashCode()方法,具目标对象未实现此方法
17 if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)){
18 return newInteger(hashCode());
19 }
20
21 //Advised接口或者其父接口中定义的方法,直接反射调用,不应用通知
22 if (!this.advised.opaque &&method.getDeclaringClass().isInterface()
23 &&method.getDeclaringClass().isAssignableFrom(Advised.class)) {
24 // Service invocations onProxyConfig with the proxy config...
25 return AopUtils.invokeJoinpointUsingReflection(this.advised,method, args);
26 }
27
28 Object retVal = null;
29
30 if (this.advised.exposeProxy) {
31 // Make invocation available ifnecessary.
32 oldProxy = AopContext.setCurrentProxy(proxy);
33 setProxyContext = true;
34 }
35
36 //获得目标对象的类 ,获得之后就可以对类进行修改等操作了
37 target = targetSource.getTarget();
38 if (target != null) {
39 targetClass = target.getClass();
40 }
41
42 //获取可以应用到此方法上的Interceptor列表 (拦截器链,为环绕通知做准备)
43 List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method,targetClass);
44
45 //如果没有可以应用到此方法的通知(Interceptor),此直接反射调用 method.invoke(target, args)
46 if (chain.isEmpty()) {
47 retVal = AopUtils.invokeJoinpointUsingReflection(target,method, args);
48 } else {
49 //创建MethodInvocation
50 invocation = newReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
51 retVal = invocation.proceed();
52 }
53
54 // Massage return value if necessary.
55 if (retVal != null && retVal == target &&method.getReturnType().isInstance(proxy)
56 &&!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
57 // Special case: it returned"this" and the return type of the method
58 // is type-compatible. Notethat we can't help if the target sets
59 // a reference to itself inanother returned object.
60 retVal = proxy;
61 }
62 return retVal;
63 } finally {
64 if (target != null && !targetSource.isStatic()) {
65 // Must have come fromTargetSource.
66 targetSource.releaseTarget(target);
67 }
68 if (setProxyContext) {
69 // Restore old proxy.
70 AopContext.setCurrentProxy(oldProxy);
71 }
72 }
73}
主流程可以简述为:获取可以应用到此方法上的通知链(Interceptor Chain),如果有,则应用通知,并执行joinpoint; 如果没有,则直接反射执行joinpoint。而这里的关键是通知链是如何获取的以及它又是如何执行的,下面逐一分析下
(5)Advised.getInterceptorsAndDynamicInterceptionAdvice()
首先,从上面的代码可以看到,通知链是通过Advised.getInterceptorsAndDynamicInterceptionAdvice()这个方法来获取的,我们来看下这个方法的实现:
1public List
可以看到实际的获取工作其实是由AdvisorChainFactory. getInterceptorsAndDynamicInterceptionAdvice()这个方法来完成的,获取到的结果会被缓存。
(6)getInterceptorsAndDynamicInterceptionAdvice()
下面来分析下这个方法的实现:
1/**
2* 从提供的配置实例config中获取advisor列表,遍历处理这些advisor.如果是IntroductionAdvisor,
3* 则判断此Advisor能否应用到目标类targetClass上.如果是PointcutAdvisor,则判断
4* 此Advisor能否应用到目标方法method上.将满足条件的Advisor通过AdvisorAdaptor转化成Interceptor列表返回.
5*/
6publicList getInterceptorsAndDynamicInterceptionAdvice(Advised config, Methodmethod, Class targetClass) {
7 // This is somewhat tricky... we have to process introductions first,
8 // but we need to preserve order in the ultimate list.
9 List interceptorList = new ArrayList(config.getAdvisors().length);
10
11 //查看是否包含IntroductionAdvisor
12 boolean hasIntroductions = hasMatchingIntroductions(config,targetClass);
13
14 //这里实际上注册一系列AdvisorAdapter,用于将Advisor转化成MethodInterceptor
15 AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
16
17 Advisor[] advisors = config.getAdvisors();
18 for (int i = 0; i 19 Advisor advisor = advisors[i];
20 if (advisor instanceof PointcutAdvisor) {
21 // Add it conditionally.
22 PointcutAdvisor pointcutAdvisor= (PointcutAdvisor) advisor;
23 if(config.isPreFiltered() ||pointcutAdvisor.getPointcut().getClassFilter().matches(targetClass)) {
24 //TODO: 这个地方这两个方法的位置可以互换下
25 //将Advisor转化成Interceptor
26 MethodInterceptor[]interceptors = registry.getInterceptors(advisor);
27
28 //检查当前advisor的pointcut是否可以匹配当前方法
29 MethodMatcher mm =pointcutAdvisor.getPointcut().getMethodMatcher();
30
31 if (MethodMatchers.matches(mm,method, targetClass, hasIntroductions)) {
32 if(mm.isRuntime()) {
33 // Creating a newobject instance in the getInterceptors() method
34 // isn't a problemas we normally cache created chains.
35 for (intj = 0; j < interceptors.length; j++) {
36 interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptors[j],mm));
37 }
38 } else {
39 interceptorList.addAll(Arrays.asList(interceptors));
40 }
41 }
42 }
43 } else if (advisor instanceof IntroductionAdvisor){
44 IntroductionAdvisor ia =(IntroductionAdvisor) advisor;
45 if(config.isPreFiltered() || ia.getClassFilter().matches(targetClass)) {
46 Interceptor[] interceptors= registry.getInterceptors(advisor);
47 interceptorList.addAll(Arrays.asList(interceptors));
48 }
49 } else {
50 Interceptor[] interceptors =registry.getInterceptors(advisor);
51 interceptorList.addAll(Arrays.asList(interceptors));
52 }
53 }
54 return interceptorList;
55}
这个方法执行完成后,Advised中配置能够应用到连接点或者目标类的Advisor全部被转化成了MethodInterceptor.
(7)chain
接下来我们再看下得到的拦截器链是怎么起作用的。
1if (chain.isEmpty()) {
2 retVal = AopUtils.invokeJoinpointUsingReflection(target,method, args);
3} else {
4 //创建MethodInvocation
5 invocation = newReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
6 retVal = invocation.proceed();
7}
从这段代码可以看出,如果得到的拦截器链为空,则直接反射调用目标方法,否则创建MethodInvocation,调用其proceed方法
(8)proceed()
触发拦截器链的执行,来看下具体代码
1 public Object proceed() throws Throwable {
2 // We start with an index of -1and increment early.
3 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size()- 1) {
4 //如果Interceptor执行完了,则执行joinPoint (通知)
5 return invokeJoinpoint();
6 }
7
8 Object interceptorOrInterceptionAdvice =
9 this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
10
11 //如果要动态匹配joinPoint (joinPoint 对象注入)
12 if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher){
13 // Evaluate dynamic method matcher here: static part will already have
14 // been evaluated and found to match.
15 InterceptorAndDynamicMethodMatcher dm =
16 (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
17 //动态匹配:运行时参数是否满足匹配条件
18 if (dm.methodMatcher.matches(this.method, this.targetClass,this.arguments)) {
19 //执行当前Intercetpor
20 returndm.interceptor.invoke(this);
21 }
22 else {
23 //动态匹配失败时,略过当前Intercetpor,调用下一个Interceptor
24 return proceed();
25 }
26 }
27 else {
28 // It's an interceptor, so we just invoke it: The pointcutwill have
29 // been evaluated statically before this object was constructed.
30 //执行当前Intercetpor
31 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
32 }
33}
4.总结
(1)加载配置信息解析成AopConfig(IOC是解析成BeanDefinition)
(2)交给AopProxyFactory,调用一个createAopProxy方法
(3)JdkDynamicAopProxy调用AdvisedSupport的getInsterceptorsAdnDynamicInterceptionAdvice方法得到拦截器链,并保存到一个List容器(IOC容器是Map)
(4)递归执行拦截器proceed()方法
5.简单实现源码
简单源码实现:https://blog.csdn.net/charjay_lin/article/details/80948427