Spring中的两种代理模式的实现原理
代理模式
Jdk动态代理
通过反射机制,创建一个代理类对象实例并返回。用户进行方法调用时使用创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,在包装方法是调用真正的业务方法)、接口、handler实现类,被代理的对象必须实现了某一个接口。
public <T> T getProxy(T target) {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), new MyInvocationHandler(
target));
}
CGLIB动态代理
一个java字节码的生成工具,它动态生成一个被代理类的子类,子类重写被代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑,通过增强器Enhancer和拦截器MethodInterceptor去实现。
创建代理的步骤:
生成代理类的二进制字节码文件;
加载二进制字节码,生成Class对象;
通过反射机制获得实例构造,并创建代理类对象
public static <T> T getObjectProxy(T target, Callback[] callbacks,
CallbackFilter filter) {
// 1、创建加强器用来创建动态代理
Enhancer enhancer = new Enhancer();
// 2 、为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
enhancer.setSuperclass(target.getClass());
// 3、 设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
// 3.1callback用于类的所有方法进行加强后返回
// enhancer.setCallback(callback);
// 3.2callbacks对指定的方法进行拦截,需要配置拦截链CallbackFilter
enhancer.setCallbacks(callbacks);
enhancer.setCallbackFilter(filter);
// 4、创建动态代理类对象并返回
return (T) enhancer.create();
}
Spring创建动态代理
AbstractAutoProxyCreator根据配置获取到所有可以引用bean的增强器List以后,就需要为bean创建代理,Spring代理又分为JDK动态代理和CGLIB动态代理两种方式,所以按照常规方式,需要一个ProxyFactory去根据需求创建具体的Proxy对象,Spring也是这么去做的。
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
//1、获取当前类钟的属性
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
//2、添加代理接口
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
//3、封装Advisor到ProxyFactory中
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
for (Advisor advisor : advisors) {
proxyFactory.addAdvisor(advisor);
}
//4、设置要代理的类
proxyFactory.setTargetSource(targetSource);
//5、定制代理,子类扩展方法
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//6、进行获取代理
return proxyFactory.getProxy(getProxyClassLoader());
}
创建代理的过程
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);
}
}
optimize:默认false,用来控制通过CGLIB创建的代理是否使用激进的优化策略。除非完全了解AOP代理如何处理优化,否则不推荐使用这个设置,目前这个属性仅仅用于CGLIB代理,JDK动态代理无效。
proxyTargetClass:默认false,<aop:aspectj-autoproxy />有一个proxy-target-class属性,当该值被设置为true时,CGLIB代理将被创建。
hasNoUserSuppliedProxyInterfaces:是否存在代理接口,代理目标没有实现接口,或者仅有一个SpringProxy接口时返回true。
CGLIB与动态代理的区别:
1、JDK动态代理只能对实现了接口的类生成代理,而不能针对类。
2、CGLIB是针对类实现代理,主要是针对指定类生成一个子类,覆盖其中的方法,因为是继承关系,所欲该类或刚发最好不要声明成final(不能被子类继承)。
无论是ObjenesisCglibAopProxy还是JdkDynamicAopProxy都实现了AopProxy,都有一个AdvisedSupport,也是前面已经初始化过的ProxyFactory。
JdkDynamicAopProxy
实现了AopProxy,同时InvocationHandler接口,核心方法就两个:
getProxy:获取代理
invoke:目标方法在调用时进行拦截。
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
被代理的类自调用
SpringAop在运行过程中通过动态代理进入到invoke,然后判断是否需要进行方法拦截,需要的时候才会根据配置生成拦截器链。但自调用是没有代理对象的,在spring的事物处理中,有时候出现类似的问题,我们可以通过<aop:aspectj-autoproxy expose-proxy=“true”/>在自调用的时候将代理对象暴露出来。
原案例:
public String getStr(String str) {
clear();
return str;
}
public class TestAop {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("META-INF/aop/spring-aop.xml");
TestC c = ctx.getBean(TestC.class);
c.getStr("test");
}
// 配置 <aop:aspectj-autoproxy expose-proxy="false"/>
结果:
Constructor of TestC
LogBean#beforePoint
使用<aop:aspectj-autoproxy expose-proxy=“true”/>
public String getStr() {
TestC testC = (TestC)AopContext.currentProxy();
testC.clear();
return str;
}
结果:
Constructor of TestC
LogBean#beforePoint
LogBean#beforePoint
expose-proxy="true"是在什么时候通过什么样的方式将自调用的代理给暴露出来的,其原理就在JdkDynamicAopProxy的invoke方法中,通过判断expose-proxy的值,是否将当前对象的代理给暴露出来。
// 其余代码省略
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 其余代码省略
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
至于invoke方法中,关于如何将增强器封装成拦截器链,然后通过递归去实现责任链的方式就不仔细详解,想知道具体的方法,可以去看DefaultAdvisorChainFactory关于这一段的实现。
// 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();
CglibAopProxy
与JDK动态代理不同的是,CglibAopProxy除了实现AopProxy并没实现其它特别接口。是通过MethodInterceptor来实现方法的拦截,与jdk动态代理处理的方式一模一样。
包含的步骤:
1、是否需要创建代理;
2、Object类的方法处理;
3、expose-proxy="true"的处理;
4、将Advisor封装成ReflectiveMethodInvocation(拦截器链)对代理对象进行处理。
CglibAopProxy的getCallbacks方法中最核心的一段代码:
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
// ... 省略
Callback[] mainCallbacks = new Callback[] {
aopInterceptor, // for normal advice
targetInterceptor, // invoke target without considering advice, if optimized
new SerializableNoOp(), // no override for methods mapped to this
targetDispatcher, this.advisedDispatcher,
new EqualsInterceptor(this.advised),
new HashCodeInterceptor(this.advised)
};
进入DynamicAdvisedInterceptor能感受到其本质与jdk动态代理是一致的。
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
private final AdvisedSupport advised;
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class<?> targetClass = null;
Object target = null;
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we
// "own" the target, in case it comes from a pool...
target = getTarget();
if (target != null) {
targetClass = target.getClass();
}
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// 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 = methodProxy.invoke(target, argsToUse);
}
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 {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
@Override
public boolean equals(Object other) {
return (this == other ||
(other instanceof DynamicAdvisedInterceptor &&
this.advised.equals(((DynamicAdvisedInterceptor) other).advised)));
}
/**
* CGLIB uses this to drive proxy creation.
*/
@Override
public int hashCode() {
return this.advised.hashCode();
}
protected Object getTarget() throws Exception {
return this.advised.getTargetSource().getTarget();
}
protected void releaseTarget(Object target) throws Exception {
this.advised.getTargetSource().releaseTarget(target);
}
}
JDK动态代理使用的ReflectiveMethodInvocation去处理,CglibAopProxy使用CglibMethodInvocation去处理,CglibMethodInvocation与ReflectiveMethodInvocation是父类与子类的关系,两者都是用同样的过程去处理bean调用时的方法。
无论是JDK动态代理还是CGLIB动态代理,都无法对private方法进行处理,所以private修饰的方法是没有AOP机制的。对于JDK动态代理是基于接口去做代理,接口的方法都是public 修饰的;CGLIB虽然是基于类去生成代理,private与final一样,都是无法被子类继承的。
本文地址:https://blog.csdn.net/zhouyu5408/article/details/107158121
上一篇: 浅谈初学者学习QtCreate的下载安装及使用的注意事项
下一篇: 它真的没有一丝丝羞愧