动态代理就是在不改变原代码逻辑的基础上,对代码功能进行增强。
一、Jdk动态代理
Jdk的动态代理是基于接口的,即如果想要对目标对象进行增强,目标对象一定要实现某一个接口,因为传入的参数就是接口。
在Spring
与MyBatis
的整合过程中,就是使用jdk的动态代理,对Mapper
文件进行代理,最终成为Spring
中的Bean
对象。
1、新增一个UserService接口
public interface UserService {
void show();
void test();
}
2、新增一个接口的实现类UserrServiceImpl
public class UserServiceImpl implements UserService{
@Override
public void show() {
System.out.println("aop测试show方法");
}
@Override
public void test() {
System.out.println("aop测试test方法");
}
}
3、编写Jdk动态代理测试类
public class JdkTest {
public static void main(String[] args) {
// 实例化需要被增强的对象
UserService userService = new UserServiceImpl();
// 参数:类加载器、被代理的接口数组、handler处理器
Object proxyInstance = Proxy.newProxyInstance(UserService.class.getClassLoader(),
new Class[]{UserService.class},
(proxy, method, args1) -> {
System.out.println("增强开始部分");
// 被代理对象的方法
Object invoke = method.invoke(userService, args1);
System.out.println("增强结束部分");
return invoke;
});
UserService instance = (UserService) proxyInstance;
// 调用实例的方法,此时会进入代理逻辑
instance.show();
}
}
测试结果:
增强开始部分
aop测试show方法
增强结束部分
二、Cglib动态代理
使用该方式进行功能增强的时候,相较于JDK被代理的对象不需要实现接口,可以简单的理解为要求更低。
1、对之前的UserServiceImpl类进行改造,将实现接口去掉
public class UserServiceImpl{
public void show() {
System.out.println("aop测试show方法");
}
public void test() {
System.out.println("aop测试test方法");
}
}
2、编写对应的Cglib测试代码
public class CglibTest {
public static void main(String[] args) {
// 创建被代理对象
UserServiceImpl userService = new UserServiceImpl();
// 创建一个Enhancer对象
Enhancer enhancer = new Enhancer();
// 设置对应的父子关系
enhancer.setSuperclass(UserServiceImpl.class);
// 创建MethodInterceptor单个或数组,用来处理代理逻辑
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Cglib前置增强");
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("Cglib后置增强");
return result;
}
});
// 创建对应代理对象
UserServiceImpl instance = (UserServiceImpl) enhancer.create();
// 调用show方法会进行代理
instance.show();
}
}
测试结果:
Cglib前置增强
aop测试show方法
Cglib后置增强
3、对同一个类的不同方法使用不同的代理方法
对该cglib代理测试方法进行改造。使得我们在调用show方法时,触发对应的增强功能;使用test方法的时候,不进行任何的增强操作。
setCallbacks方法内编写方法的代理逻辑
setCallbackFilter方法内编写被代理对象的方法过滤逻辑
public class CglibTest {
public static void main(String[] args) {
// 创建被代理对象
UserServiceImpl userService = new UserServiceImpl();
// 创建一个Enhancer对象
Enhancer enhancer = new Enhancer();
// 设置对应的父子关系
enhancer.setSuperclass(UserServiceImpl.class);
// 创建MethodInterceptor单个或数组,用来处理代理逻辑
enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Cglib前置增强");
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("Cglib后置增强");
return result;
}
},
// 添加多个拦截器, 该拦截器不做任何处理NoOp()
new NoOp() {
}});
// 设置回调过滤器,这里采用lam表达式
enhancer.setCallbackFilter(method -> {
if (method.getName().equals("test")){
return 1;
}else if (method.getName().equals("show")){
return 0;
}
// 默认采用第二个,即空代理
return 1;
});
// 创建对应代理对象
UserServiceImpl instance = (UserServiceImpl) enhancer.create();
// 调用show方法会进行代理
instance.show();
// 调用test方法会空代理
instance.test();
}
}
测试结果:
Cglib前置增强
aop测试show方法
Cglib后置增强
aop测试test方法
三、ProxyFactory动态代理
前面介绍了两种不同的实现动态代理的方式。在Spring的动态代理中,同样支持上面的两种不同形式的动态代理,Spring会根据代理对象的不同条件,选择使用不同的实现动态代理的方式。
它将两个不同的对象操作集中到一个ProxyFactory对象上,最终使用ProxyFactory对象来执行对应的动态代理操作。
Spring中的AOP就是使用ProxyFactory来实现的,所以下面的测试代码,我也仿造AOP部分的代码进行测试
1、编写对应的Before方法
public class BeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("代理前逻辑");
}
}
2、编写对应的After方法
public class AfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("代理后的逻辑");
}
}
3、编写对应的测试方法
public class ProxyFactoryTest {
public static void main(String[] args) {
// 创建被代理对象
UserServiceImpl userService = new UserServiceImpl();
// 创建一个ProxyFactory对象
ProxyFactory factory = new ProxyFactory();
// 设置目标对象
factory.setTarget(userService);
// 添加代理逻辑
factory.addAdvice(new BeforeAdvice());
factory.addAdvice(new AfterAdvice());
// 进行方法调用
factory.addAdvice(new MethodInterceptor() {
@Nullable
@Override
// 注意:此处的MethodInvocation是aop包下面的,不是Cglib的
public Object invoke(@Nonnull MethodInvocation invocation) throws Throwable {
System.out.println("方法调用前----");
Object proceed = invocation.proceed();
System.out.println("方法调用后----");
return proceed;
}
});
UserServiceImpl instance = (UserServiceImpl) factory.getProxy();
instance.show();
}
}
测试结果:
代理前逻辑
方法调用前----
aop测试show方法
方法调用后----
代理后的逻辑
高级版本,更细粒度的代理
通过观察addAdvice方法的底层我们可以发现,我们添加的addvice对象,最终都会封装为advisor对象
Advice + Pointcut = Advisor
Pointcut:何种条件才能满足切入点条件,即何种条件才进行Advice的代理逻辑
Advice:对应的代理逻辑
理解使用该种方式定义Advisor,对于Spring中AOP源码部分理解起着至关重要的作用!!!
四、Spring中AOP源代码分享
Spring的AOP就是通过ProxyFactory进行实现的,通过观察上面的内容我们不难发现,想要完成对一个方法的代理,大致需要以下一个步骤即可:
1. 找到符合当前Bean的所有的Advice
2. 将所有的Advice添加到ProxyFactory的对象中
3. 调用对应的方法
1、AOP方法的代理入口
类:AbstractAutoProxyCreator.class
getAdvicesAndAdvisorsForBean
:
根据bean的名字,找出所有符合条件的advice切入点最终返回的对象都是封装好的InstantiationModleAwarePointcutAdvisorImpl
集合对象,条件成立则直接返回代理对象
2、找到当前Bean的所有Advice
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
// 先找到所有Advisor类型的bean对象
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
// 再从所有切面中解析Advisor对象
if (this.aspectJAdvisorsBuilder != null)
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
类之间的关系图
3、找到符合当前Bean的所有的Advice
判断目标类是否和当前切点匹配
4、将所有的advisor对象添加ProxyFactory的对象中
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (proxyFactory.isProxyTargetClass()) {
// Explicit handling of JDK proxy targets and lambdas (for introduction advice scenarios)
if (Proxy.isProxyClass(beanClass) || ClassUtils.isLambdaClass(beanClass)) {
// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
for (Class<?> ifc : beanClass.getInterfaces()) {
proxyFactory.addInterface(ifc);
}
}
}
else {
// No proxyTargetClass flag enforced, let's apply our default checks...
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 构建proxyFactory流程,将前面找到的advisor数组添加到factory当中
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// Use original ClassLoader if bean class not locally loaded in overriding class loader
ClassLoader classLoader = getProxyClassLoader();
if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
}
return proxyFactory.getProxy(classLoader);
}
5、获得对应的Advisor责任链并调用入口
类:JdkDynamicAopProxy.class
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 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.
// 代理对象在执行方法时,筛选出匹配的Advisor,并适配成Intercepetor,构成链
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...
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())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
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;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
6、最终的调用方法位置
类:ReflectiveMethodInvocation.class
// 责任链递归调用,将责任链节点都进行调用
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);
// 如果没有匹配则递归调用proceed()方法
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
// 动态匹配,跟据参数进行方法匹配,匹配了就执行对应方法
if (dm.methodMatcher.matches(this.method, 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);
}
}
评论区