一,使用AOP
先看spring aop具体怎么使用,再分析源码。
1,xml配置方式
xml配置文件 spring.xml
<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
">
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<bean id="userService2" class="bean.UserService2" />
<bean id="beforeAdvice" class="bean.UserServiceBeforeAdvice"/>
<bean id="methodInterceptor" class="org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor">
<constructor-arg ref="beforeAdvice"/>
</bean>
<bean class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
<property name="expression" value="execution(* bean.IUserService.*(..))"/>
<property name="advice" ref="methodInterceptor"/>
</bean>
</beans>
service接口:
package bean;
public interface IUserService {
String queryUserInfo();
}
被代理的UserService实现类 , jdk代理只会代理接口,被代理的类需要实现一个接口,使用的时候用接口
package bean;
import java.util.Random;
public class UserService2 implements IUserService {
public String queryUserInfo() {
System.out.println("这是第二个方法");
return "queryUserInfo 返回值";
}
}
Advice增强类:
package bean;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class UserServiceBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("拦截方法:" + method.getName());
}
}
测试结果:
2,注解方式
<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
">
<context:property-placeholder location="beans.yml" file-encoding="UTF-8"/>
<context:component-scan base-package="bean"/>
<aop:aspectj-autoproxy />
</beans>
被代理的UserService 增强类:
package bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import java.util.Random;
@Service
public class UserService implements IUserService {
public String queryUserInfo() {
System.out.println("执行queryUserInfo方法");
try {
Thread.sleep(new Random(1).nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
return "返回值";
}
}
注解式的增强类
package bean;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Component
@Aspect
public class UserServiceAnnotationAdvice {
@Around(value="execution(* bean.IUserService.*(..))")
public Object adviceAround(ProceedingJoinPoint joinPoint) throws Throwable{
//获取连接点签名
Signature signature = joinPoint.getSignature();
//将其转换为方法签名
MethodSignature methodSignature = (MethodSignature) signature;
//通过方法签名获取被调用的目标方法
Method method = methodSignature.getMethod();
long startTime = System.currentTimeMillis();
//调用proceed方法,继续调用下一个通知
Object returnVal = joinPoint.proceed();
long endTime = System.currentTimeMillis();
long costTime = endTime - startTime;
//输出方法信息
System.out.println(String.format("%s,耗时:%s", method.toString(), costTime));
//返回方法的返回值
return returnVal;
}
}
测试效果:
二,源码剖析
1,AOP相关的几个类
Joinpoint:切点定义接口
public interface Joinpoint {
/**
* Proceed to the next interceptor in the chain.
* 得到调用链的下一个拦截器
*/
Object proceed() throws Throwable;
/**
* Return the object that holds the current joinpoint's static part.
*/
Object getThis();
/**
* Return the static part of this joinpoint.
*/
AccessibleObject getStaticPart();
}
代理类接口, jdk动态代理和cglib动态代理都实现了这个接口
package org.springframework.aop.framework;
public interface AopProxy {
/**
* 创建代理对象
* Create a new proxy object.
* <p>Uses the AopProxy's default class loader (if necessary for proxy creation):
* usually, the thread context class loader.
*/
Object getProxy();
}
InvocationHandler:
package java.lang.reflect;
public interface InvocationHandler {
/**
* 触发目标增强方法
* Processes a method invocation on a proxy instance and returns
* the result. This method will be invoked on an invocation handler
* when a method is invoked on a proxy instance that it is
* associated with.
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
jdk动态代理类 JdkDynamicAopProxy , 实现了 AopProxy 和 InvocationHandler
Interceptor拦截器接口
package org.springframework.cglib.proxy;
import java.lang.reflect.Method;
public interface MethodInterceptor extends Callback {
Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;
}
cglib动态代理类 CglibAopProxy的 DynamicAdvisedInterceptor 实现了 MethodInterceptor
2,xml配置方式
org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator //
org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor//切面 ,是一个 Advisor
org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor//切面增强类
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator// AOP核心处理类,DefaultAdvisorAutoProxyCreator的抽象父类
DefaultAdvisorAutoProxyCreator 实现了 BeanPostProcessor,代理类在创建时,spring在初始化这个(代理)类时会调用 DefaultAdvisorAutoProxyCreator的postProcessAfterInitialization方法,然后根据切面 AspectJExpressionPointcutAdvisor中的切入点AspectJExpressionPointcut(expression) 去找到当前代理类 代理方法 的所有增强 Advisor。
具体来说是在AbstractAdvisorAutoProxyCreator类的findEligibleAdvisors方法,通过PointcutAdvisor(MethodBeforeAdviceInterceptor的父接口)找到在ProxyFactory创建代理类的过程中(AbstractAutoProxyCreator中的wrapIfNecessary方法),会将所有Advisor和Advice 注入给 ProxyFactory。
最后创建代理类,代理类有两种,jdk动态代理(org.springframework.aop.framework.JdkDynamicAopProxy)或者cglib动态代理(org.springframework.aop.framework.CglibAopProxy)
AbstractAutoProxyCreator类中的createProxy方法
/**
* Create an AOP proxy for the given bean.
*/
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
//...
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
//寻找并注入被增强类的所有 Advisor,Advice
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
//...
//创建jdk动态代理或者cglib动态代理
return proxyFactory.getProxy(getProxyClassLoader());
}
如果目标类是接口 用jdk动态代理,否则用cglib动态代理
2.1 jdk动态代理
2.1.1 创建代理类:
2.1.2 为什么jdk代理类必须是接口:
因为jdk动态代理生成的类已经继承了Proxy,而java是单继承的,所以是基于jdk动态代理是基于接口的。
jdk代理的类必须传他的接口:
@Test
public void test_jdk_proxy2(){
ClassLoader classLoader= Thread.currentThread().getContextClassLoader();
IUserService target=new UserService2();
IUserService proxy= (IUserService) Proxy.newProxyInstance(classLoader,target.getClass().getInterfaces() ,(obj, method, args)->{
System.out.println(obj.getClass()+",这个类被代理了。。。");
return "代理返回值";
});
System.out.println("父类:"+proxy.getClass().getSuperclass());
for (Class<?> anInterface : proxy.getClass().getInterfaces()) {
System.out.println("接口:"+anInterface);
}
System.out.println(proxy.queryUserInfo());
byte[] bytes = ProxyGenerator.generateProxyClass("UserService", target.getClass().getInterfaces());
File file = new File("E:\\temp\\UserService.class") ;
FileOutputStream fo = null;
try {
fo = new FileOutputStream(file);
fo.write(bytes);
fo.flush();
fo.close();
} catch (Exception e) {
e.printStackTrace();
}
}
如果只传接口,没有实现类,那么他代理类将不实现接口:
如果不传接口,会报错:
查看Proxy生成代理类的方法,没看懂:
将代理类生成出来,会发现,他继承了Proxy,实现了自定义接口。
由于java只能是单继承,所以jdk代理只能是接口
2.1.3 调用被代理的方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
//各种校验。。。
Object retVal; //增强方法返回值
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 得到拦截器链,Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// 没有拦截器,直接执行目标方法
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 调用"下一个"拦截器"Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
// 处理方法返回值 Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
}
ReflectiveMethodInvocation类的 proceed 方法:
每次调用 currentInterceptorIndex 加 1,最后一次就是执行 目标方法
org.springframework.aop.framework.ReflectiveMethodInvocation#invokeJoinpoint
->org.springframework.aop.support.AopUtils#invokeJoinpointUsingReflection
不是最后一次依次执行MethodInterceptor的实现类:
2.2 cglib动态代理
org.springframework.aop.framework.CglibAopProxy,核心类是Enhancer :
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
//log...
try {
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
Class<?> proxySuperClass = rootClass;
//...
// 创建cglib的 Enhancer 。Configure CGLIB Enhancer...
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
//设置被代理的类
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
//得到回调方法 ,这个方法会初始化 DynamicAdvisedInterceptor,得到拦截器链
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance.
return createProxyClassAndInstance(enhancer, callbacks);
}
}
org.springframework.aop.framework.CglibAopProxy#getCallbacks 方法返回代理类所有的拦截器:
Callback是MethodInterceptor的父接口
配置了DynamicAdvisedInterceptor,在其中会创建ReflectiveMethodInvocation,会在调用方法时候执行
最终cglib会调用被增强类的构造方法。这也是为什么cglib动态代理可以代理 实现类
Enhancer#create生成代理类对象。生成类是使用 ASM 进行生成。
用如下方法可以保存生成代理类的字节码文件:
@Test
public void test_scan_aop_cglib() {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\\temp\\cglib");
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-scan.xml");
UserServiceCglib userService = applicationContext.getBean("userServiceCglib", UserServiceCglib.class);
System.out.println("测试结果:" + userService.queryUserInfo());
}
可以看到生成的代理类继承了目标类,并且方法是final的,所以cglib动态代理的类不能是final的
3,注解方式
需要在xml里配置 <aop:aspectj-autoproxy />,或者springboot用特殊的starter。
加载了 org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator,这个类是 AbstractAutoProxyCreator 的子类。处理方式和上边一样。