文章摘要(AI生成)
前置-动态代理示例代码如下:public interface UserService { void add(); void remove();}public class UserServiceImpl implements UserService{public void add(){Sy
前言-动态代理
示例代码如下:
public interface UserService { void add(); void remove(); } public class UserServiceImpl implements UserService{ public void add(){ System.out.println("添加用户"); } public void remove(){ System.out.println("删除用户"); } }
我们的代理对象实现为:
public class UserServiceProxy implements MethodInterceptor, InvocationHandler { //JDK动态代理 private final UserService userService; public UserServiceProxy(UserService userService) { this.userService = userService; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("JDK Start..."); Object result = method.invoke(userService, args); System.out.println("JDK End"); return result; } //Cglib动态代理 @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("Cglib Start..."); Object result = methodProxy.invokeSuper(o, objects); System.out.println("Cglib End"); return result; } } public class Demo{ public static void main(String[] args) { UserService userService = new UserServiceImpl(); UserServiceProxy userServiceProxy = new UserServiceProxy(userService); //jdk代理对象调用 ClassLoader classLoader = DemoTest.class.getClassLoader(); userService = (UserService) Proxy.newProxyInstance(classLoader, new Class[]{UserService.class}, userServiceProxy); userService.add(); //Cglib代理对象调用 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserServiceImpl.class); enhancer.setCallback(userServiceProxy); userService = (UserService)enhancer.create(); userService.add(); } }
在使用JDK动态代理时,我们的代理目标是接口,而使用Cglib代理时,我们的代理目标是对象:
代理模式的实践-AOP
spring AOP是通过动态代理拓展代理对象原有功能的集大成者,他通过代理链的方式层层叠加,完成我们对代理对象的层层拓展。
在我们通过spring IOC获取bean的时候,spring AOP通过实现BeanPostProcessor
,返回对应的代理对象:
实例化前置处理
而bean实例化前的前置处理中调用了postProcessBeforeInstantiation
方法,该方法(位置在:AbstractAutoProxyCreator
)主要做了以下流程:
- 如果该bean未被处理过:
- 指定的增强器中含有该bean,则返回null
- 如果bean是基础设施类或设置为不代理,则返回null
- 如果bean有定制的目标源:
- 获取bean对应的增强器
- 根据对应的增强器创建代理
- 返回代理对象
- 上述流程都没走到,则返回null
流程示意图如下:
可以看到主要处理在bean是否有自定义的targetSource
,如果有,则对自定义的targetSource
创建代理。否则返回null走bean的创建流程。
对于自定义targetSource的使用,我们可以参考spring官方文档:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-targetsource
初始化后置处理
在bean初始化时,通过调用postProcessAfterInitialization
方法,完成代理类的创建:
- 根据给定的bean生成代理对象的key
- 如果需要被代理,则获取指定的代理bean:
- 如果该bean已被处理过,则直接返回bean对象
- 如果指定的切面不含有该bean,则直接返回bean对象
- 如果bean是基础设施类或被设置不代理,则直接返回bean对象
- 获取bean对应的增强器
- 根据对应的增强器创建代理
- 返回代理对象
流程图如下所示:
代理增强器
上述流程我们总结下来,代理对象的创建一共有两步:
- 通过
getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null)
方法获取作用域指定bean上的所有增强器 - 调用
createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean))
方法创建指定切面的代理增强器
增强器获取
切面获取主要流程为:
- 获取所有切面作为候选增强器(
findCandidateAdvisors
); - 过滤出候选切面中的可用增强器(
findAdvisorsThatCanApply
) - 拓展可用增强器(对AspectJ的支持)
- 按
@Ordered
优先级对切面进行排序
在获取所有切面中,有两种实现一种是获取xml中的增强器,一种是获取注解中声明的增强器。我们常用的注解前置通知、环绕通知、后置通知等都是通过增强器获取工厂ReflectiveAspectJAdvisorFactory
获取到的:
@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
//获取候选增强方法的aspectJ注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// 检查对应的类是否有相应注解
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}
if (logger.isDebugEnabled()) {
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
}
AbstractAspectJAdvice springAdvice;
//判断注解类型,返回不同的AOP增强器
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
// Now to configure the advice...
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
增强器概览
通过上述增强器获取的代码中,我们可以知道常用的通知和其实现类对应为:
通知类型 | 增强器 |
---|---|
环绕通知 | AspectJAroundAdvice |
前置通知 | AspectJMethodBeforeAdvice |
后置通知 | AspectJAfterAdvice |
最终通知 | AspectJAfterReturningAdvice |
异常通知 | AspectJAfterThrowingAdvice |
增强器主要由两个作用:执行我们对代理方法的增强功能invokeAdviceMethod
,以及调用下一个增强器proceed
上述5个通知中,我们依次看调用逻辑:
环绕通知:只执行增强方法,下一个增强器的调用不做实现
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
JoinPointMatch jpm = getJoinPointMatch(pmi);
return invokeAdviceMethod(pjp, jpm, null, null);
}
前置通知:先调用增强方法,再调用下一个增强器
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
@Override
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
后置通知:不管调用下一个增强器的过程是否出现异常,也要执行增强方法
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
最终通知:先调用下一个增强器获取返回值,再调用增强方法
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
@Override
public void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable {
if (shouldInvokeOnReturnValueOf(method, returnValue)) {
invokeAdviceMethod(getJoinPointMatch(), returnValue, null);
}
}
异常通知:当调用下一个增强器的过程出现异常时,执行增强方法
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
上述我们增强器的完整调用,即是使用我们的责任链模式进行实现:
具体的实现逻辑在ReflectiveMethodInvocation.proceed()
这个方法中,该方法采用递归方式,流程图示如下:
创建代理
代理对象的第二步,即调用 createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean))
方法创建代理对象,接下来我们看代理是如何完成创建的。
代理工厂
AOP通过代理工厂DefaultAopProxyFactory
中的createAopProxy
方法完成Aop代理的创建:
- 如果使用优化的代理配置或者目标类为接口代理或者仅指定了
SpringProxy
接口- 如果代理对象为接口,则使用JDK动态代理
- 否则使用CGLIB代理
- 除了上述条件外的其他条件则使用JDK动态代理
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
动态代理类
JDK动态代理和CGLIB动态代理的实现跟我们自己实现时一样,只需要按照对应的规范进行填充即可。
JDK动态代理
例如JdkDynamicAopProxy
,本身只有两个核心方法,分别是获取代理对象getProxy
和代理方法执行invoke
.
获取代理对象的代码与我们自己实现时相同,也是调用JDK的Proxy.newProxyInstance
进行代理对象的创建:
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
而JdkDynamicAopProxy
本身则实现了InvocationHandler
接口,在invoke
方法里执行了代理过程
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 {
//省略:前置条件判断的流程
Object retVal;
if (this.advised.exposeProxy) {
// 暂存当前代理,使调用可用。
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 尽可能晚,以尽量减少我们“拥有”目标的时间,以防它来自池。
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 获取此方法的拦截链。
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 检查我们是否有任何advice。 如果为空直接反射调用代理方法,并避免创建 MethodInvocation。
if (chain.isEmpty()) {
// 我们可以跳过创建 MethodInvocation:直接调用目标方法
// 请注意,最终调用者必须是 InvokerInterceptor,因此我们知道它除了对目标进行反射操作外什么都不做,没有热交换或花哨的代理。
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 我们需要创建一个方法调用...
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 通过拦截器链进入连接点。
retVal = invocation.proceed();
}
// 返回值按返回类型进行转换
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// 特殊情况:它返回“this”并且该方法的返回类型是类型兼容的。
// 请注意,如果代理对象在另一个返回的对象中设置了对自身的引用,那么将无能为力,需要抛出异常。
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()) {
// 必须来自 TargetSource。
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// 恢复旧代理。
AopContext.setCurrentProxy(oldProxy);
}
}
}
CGLIB动态代理
CGLIB代理同样通过实现MethodInterceptor
接口创建代理。
其代理对象的获取主要在我们设置Enhancer
的回调上,其回调的获取如下:
-
如果非静态方法且拦截器链未冻结:
-
AOP拦截器的获取
-
代理方法拦截器的获取
-
-
如果是静态方法且拦截器链被冻结,则可以进行一些调用的优化
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// 设置用于优化选择的参数...
boolean exposeProxy = this.advised.isExposeProxy();
boolean isFrozen = this.advised.isFrozen();
boolean isStatic = this.advised.getTargetSource().isStatic();
// 选择一个“aop”拦截器(用于 AOP 调用)。).
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
// 选择“直达目标”拦截器(用于未经过增强器但可以返回的调用)。可能需要公开代理。
Callback targetInterceptor;
if (exposeProxy) {
targetInterceptor = (isStatic ?
new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
}
else {
targetInterceptor = (isStatic ?
new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
}
// 选择一个“直接到目标”调度程序(用于对无法返回此的静态目标的未经增强器的调用)。
Callback targetDispatcher = (isStatic ?
new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());
Callback[] mainCallbacks = new Callback[] {
aopInterceptor, // 正常增强器
targetInterceptor, // 调用目标而不考虑增强器,如果优化
new SerializableNoOp(), // 没有覆盖映射到此的方法
targetDispatcher, this.advisedDispatcher,
new EqualsInterceptor(this.advised),
new HashCodeInterceptor(this.advised)
};
Callback[] callbacks;
// 如果目标是静态的并且增强器链被冻结,那么我们可以通过使用该方法的固定链将 AOP 调用直接发送到目标来进行一些优化。
if (isStatic && isFrozen) {
//。。。省略此处代码
}
else {
callbacks = mainCallbacks;
}
return callbacks;
}
而在AOP拦截器中,我们可以看到跟我们自己调用CGLIB时相同的代码
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
// 与AOP中invoke相同的代码,不再重复
else {
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
// 与AOP中invoke相同的代码,不再重复
}
}
评论区