
使用cglib方式动态代理Bean
某些时候我们需要无感的对一些方法或类进行操作,可以使用@Aspect注解即可以找到已知目标位置并实现切面拦截。本文将介绍一种在Spring体系下,未知目标(编写代码时)动态代理的方式,该方式底层基于cglib实现。
在Spring生命周期中的Bean初始化阶段找到代理目标类
在SpringBoot3x框架体系下,可以通过实现接口org.springframework.beans.factory.config.BeanPostProcessor
的方法Object postProcessBeforeInitialization(@NonNull Object bean, @NonNull String beanName) throws BeansException
来切入操作Bean初始化阶段。
代码片段:
public abstract class Example implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(@NonNull Object bean, @NonNull String beanName) throws BeansException {
//TODO: 代理操作
return bean;
}
}
创建代理类工厂并配置代理相关参数
接入Bean初始化阶段后,我们可以通过判断该Bean是否实现某个接口或继承某个类等等特性来判断该Bean是否我们的代理目标类。如果不是,我们返回原始Bean,如果是代理目标类,我们需要创建一个org.springframework.aop.framework.ProxyFactory
来代理原始Bean,并对ProxyFactory进行一些列代理相关配置,并通过ProxyFactory.getProxy()方法获取代理类(被代理覆盖后的新Bean)。其中proxyFactory.setProxyTargetClass(Boolean.TRUE)是关键代码,这句代码决定了当前代理是以方法代理创建还是以类代理创建,以类代理创建默认使用cglib实现。
代码片段:
//创建代理
ProxyFactory proxyFactory = new ProxyFactory(bean);
//启用cglib代理
proxyFactory.setProxyTargetClass(Boolean.TRUE);
String proxyMethodName = "suchSave";
//配置切面事件
proxyFactory.addAdvisor(
new DefaultPointcutAdvisor(new NameMatchMethodPointcut().addMethodName(proxyMethodName), (MethodInterceptor) invocation -> {
//TODO: 其他操作
System.out.println("触发方法前操作");
//执行方法,并获取返回值
Object ret = invocation.proceed();
System.out.println("触发方法后操作");
return ret;
}));
//获取代理对象
proxyFactory.getProxy();
完整代码
import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.NameMatchMethodPointcut;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.lang.NonNull;
import java.util.Arrays;
/**
* @author tomsean
*/
public abstract class Example implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(@NonNull Object bean, @NonNull String beanName) throws BeansException {
boolean isProxy = false;
Class<?>[] interList = bean.getClass().getInterfaces();
if (interList.length == 0) {
return bean;
}
String targetTypeName = "xxx"; //目标接口名
isProxy = Arrays.stream(interList).anyMatch(i -> i.getTypeName().equals(targetTypeName));
if (!isProxy) {
//非目标bean,返回原始bean
return bean;
}
//创建代理
ProxyFactory proxyFactory = new ProxyFactory(bean);
//启用cglib代理
proxyFactory.setProxyTargetClass(Boolean.TRUE);
String proxyMethodName = "suchSave";
//配置切面事件
proxyFactory.addAdvisor(
new DefaultPointcutAdvisor(new NameMatchMethodPointcut().addMethodName(proxyMethodName), (MethodInterceptor) invocation -> {
//TODO: 其他操作
System.out.println("触发方法前操作");
Object ret = invocation.proceed();
System.out.println("触发方法后操作");
return ret;
}));
//将代理后的新bean返回
return proxyFactory.getProxy();
}
}
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 TomSean's Blog
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果