Spring(二十),Java 中级开发笔试题及答案
setSuperClass:注入被代理的类
setCallBack:注入代理实例
create:生成完整的代理对象
使用完整的代理对象来执行被代理的类的方法,此时方法就会被代理实例给拦截到了
下面就来看看 Spring 是如何创建的,我们从获取切面的方法入手,也就是 getProxy
可以看到,对于 getProxy 的实现,是交由 CglibAopProxy 来完成的
源码如下
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
}
try {
//获取被代理对象的目标 Class(之前在构造方法上成功注入)
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
//创建另外一个变量存放目标 class
Class<?> proxySuperClass = rootClass;
//判断目标 class 的名字是不是包含 $$的字样
//包含这两个字符就比较特殊了,代表其就是一个代理对象
//此时就要代理的对象是一个代理对象
if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
//此时目标就应该为父类 class 了,也就是目标对象的被代理对象
//相当于找到了最初的被代理对象,让目标对象变成最初的被代理对象
proxySuperClass = rootClass.getSuperclass();
//获取此时被代理的代理对象的接口
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
//遍历接口添加进增强器里面
this.advised.addInterface(additionalInterface);
}
}
// Validate the class, writing log messages as necessary.
//校验,并输出日志(不重要)
validateClassIfNecessary(proxySuperClass, classLoader);
// Configure CGLIB Enhancer...
//接下来就是 Cglib 创建代理的步骤啦
//创建 Enhancer(Enhancer 就是用来根据代理实例来增强被代理类的)
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
//设置被代理类,可以看到这里使用的是 proxySuperClass(如果是代理对象,那么 proxySuperClass 会为父类)
enhancer.setSuperclass(proxySuperClass);
//通常配置
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
//设置拦截器
Callback[] callbacks = getCallbacks(rootClass);
//获取拦截器的所有类型
//用于注入进 enhancer
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// 给 enhancer 注入拦截器链
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
//注入 callBack 的类型,callBack 就是拦截器
enhancer.setCallbackTypes(types);
//使用 enhancer 生成代理对象
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
获取被代理的目标对象
获取 proxySupperClass,proxySupperClass,其实是真正的目标对象,为什么是真正呢?
判断要被代理的目标对象有没有这两个关键字,这两个关键字,出现这两个关键字就相当于被代理的目标对象已经是一个代理对象了,一般 Cglib 的代理 Class 的 name 是类名 E n h a n c e r B y C G L I B EnhancerByCGLIB EnhancerByCGLIB
如果目标对象是一个 Cglib 代理对象,获取其父类,将父类的所有接口都添加进拦截器链中
校验操作
创建 Enhancer
注入属性进去 Enhancer,比如代理对象的类型、策略、拦截器集合、拦截器集合对应的类型集合
最终使用 Enhancer 创建代理对象
拦截器链如何形成
对应的方法就是 getCallbacks 方法
该方法源码如下
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// Parameters used for optimization choices...
//判断是不是要进行曝光
boolean exposeProxy = this.advised.isExposeProxy();
boolean isFrozen = this.advised.isFrozen();
boolean isStatic = this.advised.getTargetSource().isStatic();
// 使用 advised 创建 DynamicAdvisedInterceptor,里面就是前面定义的拦截器了
//要记住此时 advised 里面拥有着被代理 Bean 的信息,和所有的拦截器
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
// Choose a "straight to target" interceptor. (used for calls that are
// unadvised but can return this). May be required to expose the proxy.
Callback targetInterceptor;
//判断是否要曝光
//根据是否要曝光并且是动态代理还是静态代理去生成拦截器
//这里的 targetInterceptor 拦截器称为目标拦截器
//这个拦截器的作用实质上没有对方法进行增强,但里面的额外操作会将当前代理对象切面曝光出来
//Cglib 还支持静态代理咧。。。
if (exposeProxy) {
//如果要曝光,对应要创建 exposedInterceptor
//并且从创建方法可以看到,直接给了目标对象,并没有给增强器
//在这里 exposedInterceptor 是会对代理对象进行曝光的
targetInterceptor = (isStatic ?
new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
}
else {
//如果不需要曝光,创建 unadvvisedInterceptor,从名字就可以看出,是一个没有增强器的拦截器
//但其实还会对返回值做一些处理
targetInterceptor = (isStatic ?
new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
}
// Choose a "direct to target" dispatcher (used for
// unadvised calls to static targets that cannot return this).
// 创建 targetDispatcher,这个跟 unadvisedInterceptor 的作用其实差不多
// 直接执行目标对象的方法,本质上没有做其他任何其他增强操作,不过可能会对返回值做一些处理
Callback targetDispatcher = (isStatic ?
new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());
//组装所有的拦截器
Callback[] mainCallbacks = new Callback[] {
//第一位是我们定义的那些 AOP 拦截
aopInterceptor, // for normal advice
//第二位是 targetInterceptor,也就是是否曝光的拦截器
targetInterceptor, // invoke target without considering advice, if optimized
//第三位是真的什么都不增强,只去执行目标对象的方法
//这个 SerializableNoOp 其实本是上就是 cglib 的 NoOp
new SerializableNoOp(), // no override for methods mapped to this
//第四位是 targetDispatcher
targetDispatcher, this.advisedDispatcher,
//第五位是 equal 方法的拦截器
new EqualsInterceptor(this.advised),
//第六位是 hashCode 方法的拦截器
new HashCodeInterceptor(this.advised)
};
Callback[] callbacks;
// If the target is a static one and the advice chain is frozen,
// then we can make some optimizations by sending the AOP calls
// direct to the target using the fixed chain for that method.
//如果目标对象是静态的或者拦截器链是冻结的
//这里会做一些修复措施
if (isStatic && isFrozen) {
//获取代理对象类型的所有方法
Method[] methods = rootClass.getMethods();
Callback[] fixedCallbacks = new Callback[methods.length];
this.fixedInterceptorMap = CollectionUtils.newHashMap(methods.length);
// TODO: small memory optimization here (can skip creation for methods with no advice)
//遍历目标对象类型的所有方法
for (int x = 0; x < methods.length; x++) {
//当前的方法
Method method = methods[x];
//获取目标当前的方法需要执行的拦截器链,每个方法要进行的拦截器链都不一样
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
//封装成 FixedChainStaticTargetInterceptor 存放进 fixedCallBacks 中
fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
this.fixedInterceptorMap.put(method, x);
}
// Now copy both the callbacks from mainCallbacks
// and fixedCallbacks into the callbacks array.
//将三个 callBacks 都集合起来
callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
this.fixedInterceptorOffset = mainCallbacks.length;
}
else {
callbacks = mainCallbacks;
}
//最终返回整个 callbacks
return callbacks;
}
可以看到,这里的拦截器链形成不单单只针对我们设置的 AOP 的拦截器链,还有额外的一些提前曝光的拦截器链
aopInterceptor
targetInterceptor
SerialbleNoOp
targetDispatcher
而决定适用哪些拦截器链的由传进给 Enhancer 的 ProxyCallbackFilter 来进行
自定义拦截
从代码上可以看到,对于拦截器链,是 CglibAopProxy 里面的一个 ProxyCallBackFilter,该内部类实现了 CallbackFilter 接口(Cglib 的接口),那么对应的肯定会实现 accept 方法,先来说一下这个 CallbackFilter 的作用,顾名思义它是一个过滤接口,用来过滤回调的方法的,说白了,accept 方法可以给方法自定义要执行的增强器,即哪些方法执行对应的增强器,该方法返回的是一个整形,该返回值对应的就是注入进 Enhancer 里面的拦截器集合(setCallbaks 方法,该方法在最终使用 Enhancer 创建代理对象时调用)的索引值,根据这个索引值去找到拦截器
该方法的源码如下
public int accept(Method method) {
//判断当前方法是不是 final 类型
//如果是 final 类型,代表不能重写
if (AopUtils.isFinalizeMethod(method)) {
logger.trace("Found finalize() method - using NO_OVERRIDE");
//返回 2
return NO_OVERRIDE;
}
//如果方法是来自于接口的,并且实现的 Class 是一个 Advise
//那就说明
if (!this.advised.isOpaque() && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
if (logger.isTraceEnabled()) {
logger.trace("Method is declared on Advised interface: " + method);
}
return DISPATCH_ADVISED;
}
// We must always proxy equals, to direct calls to this.
//如果执行 equals 方法,适用 Equals 方法的拦截器
if (AopUtils.isEqualsMethod(method)) {
if (logger.isTraceEnabled()) {
logger.trace("Found 'equals' method: " + method);
}
return INVOKE_EQUALS;
}
//如果适用 HashCode,同样适用 HashCode 的拦截器
// We must always calculate hashCode based on the proxy.
if (AopUtils.isHashCodeMethod(method)) {
if (logger.isTraceEnabled()) {
logger.trace("Found 'hashCode' method: " + method);
}
return INVOKE_HASHCODE;
}
Class<?> targetClass = this.advised.getTargetClass();
// Proxy is not yet available, but that shouldn't matter.
//获取拦截器链
List<?> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
boolean haveAdvice = !chain.isEmpty();
boolean exposeProxy = this.advised.isExposeProxy();
boolean isStatic = this.advised.getTargetSource().isStatic();
boolean isFrozen = this.advised.isFrozen();
//如果拥有拦截器链
if (haveAdvice || !isFrozen) {
// If exposing the proxy, then AOP_PROXY must be used.
//并且代理对象会被曝光
if (exposeProxy) {
if (logger.isTraceEnabled()) {
logger.trace("Must expose proxy on advised method: " + method);
}
//适用 AOP 的拦截器链
return AOP_PROXY;
}
// Check to see if we have fixed interceptor to serve this method.
// Else use the AOP_PROXY.
if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(method)) {
if (logger.isTraceEnabled()) {
logger.trace("Method has advice and optimizations are enabled: " + method);
}
// We know that we are optimizing so we can use the FixedStaticChainInterceptors.
int index = this.fixedInterceptorMap.get(method);
return (index + this.fixedInterceptorOffset);
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Unable to apply any optimizations to advised method: " + method);
}
//适用 AOP 的拦截器链
return AOP_PROXY;
}
}
else {
// See if the return type of the method is outside the class hierarchy of the target type.
// If so we know it never needs to have return type massage and can use a dispatcher.
// If the proxy is being exposed, then must use the interceptor the correct one is already
// configured. If the target is not static
, then we cannot use a dispatcher because the
// target needs to be explicitly released after the invocation.
//如果 AOP 拦截器链是空的,使用 targetIntercetor,不进行增强了执行目标对象的方法
if (exposeProxy || !isStatic) {
return INVOKE_TARGET;
}
Class<?> returnType = method.getReturnType();
if (targetClass != null && returnType.isAssignableFrom(targetClass)) {
if (logger.isTraceEnabled()) {
logger.trace("Method return type is assignable from target type and " +
"may therefore return 'this' - using INVOKE_TARGET: " + method);
}
return INVOKE_TARGET;
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Method return type ensures 'this' cannot be returned - " +
"using DISPATCH_TARGET: " + method);
}
return DISPATCH_TARGET;
}
}
}
评论