源码学习之AOP-代理对象的生成
Posted 刘老c
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了源码学习之AOP-代理对象的生成相关的知识,希望对你有一定的参考价值。
在Spring AOP中,创建代理对象是很重要的一部分内容,还记得之前写的代理模式的那篇文章么,在那个里面,我们封装了一个getProxy()方法,用来返回生成的代理对象,其实这个就是模仿的Spring的写法,Spring通过AopProxy提供接口方法getProxy()用来获取代理对象,具体的实现则是交由自己的子类实现。
AopProxy
我们先来认识一下AopProxy:
AopProxy:
/**
* Delegate interface for a configured AOP proxy, allowing for the creation
* of actual proxy objects.
*
* <p>Out-of-the-box implementations are available for JDK dynamic proxies
* and for CGLIB proxies, as applied by {@link DefaultAopProxyFactory}.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @see DefaultAopProxyFactory
*/
public interface AopProxy {
/**
* Create a new proxy object.
* <p>Uses the AopProxy's default class loader (if necessary for proxy creation):
* usually, the thread context class loader.
* @return the new proxy object (never {@code null})
* @see Thread#getContextClassLoader()
*/
Object getProxy();
/**
* Create a new proxy object.
* <p>Uses the given class loader (if necessary for proxy creation).
* {@code null} will simply be passed down and thus lead to the low-level
* proxy facility's default, which is usually different from the default chosen
* by the AopProxy implementation's {@link #getProxy()} method.
* @param classLoader the class loader to create the proxy with
* (or {@code null} for the low-level proxy facility's default)
* @return the new proxy object (never {@code null})
*/
Object getProxy(ClassLoader classLoader);
}
Spring 通过AopProxy接口,它通过getProxy()用来提供代理对象,他有两个子类,对应通过JDK和CGLIB生成的代理对象:
JdkDynamicAopProxy
简单回顾一下,在之前代理模式中,我们的jdk动态代理的实现主要是通过实现InvocationHandler,代理对象的获取则是通过Proxy.new ProxyInstance(ClassLoader,Interface,InvocationHandler)完成,现在我们看下Spring中的实现:
JdkDynamicAopProxy
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
//省略部分代码
@Override
public Object getProxy() {
return getProxy(ClassUtils.getDefaultClassLoader());
}
@Override
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);
}
}
可以看到,在获取代理对象这部分,Spring的实现过程也是类似的,通过调用Proxy的newProxyInstance方法,获取对应的代理对象。三个参数:一个是类加载器,一个是代理接口,还有一个就是实现了InvocationHandler接口的对象作为回调入口。
CglibAopProxy
在代理模式中,我们cglib动态代理的代理对象是通过Enhancer对象返回的,当时我们设置了它的两个属性:enhancer.setSuperClass(),enhancer.setCallBack(),前者用来设置代理目标,后者用来设置回调,也就是设置拦截器,我们看下Spring中的cglib动态代理对象是怎么获取的:
CglibAopProxy:
@Override
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
}
try {
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
Class<?> proxySuperClass = rootClass;
if (ClassUtils.isCglibProxyClass(rootClass)) {
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...
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance.
return createProxyClassAndInstance(enhancer, callbacks);
}
Enhancer对象是cglib中的主要操作类,我们通过它来返回代理对象,在之前的代理模式中,我们只使用到了enhancer.setsuperclass()和enhancer.setCallBack()这两个属性,前者用来设置目标对象,后者用来设置回调入口,最后通过enhancer.create()返回代理对象。
在CglibAopProxy中,同样使用的是enhancer对象,只不过spring中设置的属性更加完善:
比如通过enhancer.setCallbacks()添加了多个拦截器,
又通过enhancer.setCallBackFilter()对具体使用的拦截器做了处理。
最后还是通过enhancer.create()返回代理对象。
CallbackFilter
这里简单的说明下CallbackFilter这个接口,通过实现这个接口重写其中的accept()方法,可以根据场景选择对应的拦截器来处理,返回的int值是回调方法中的序值:
/**
* CallbackFilter to assign Callbacks to methods.
*/
private static class ProxyCallbackFilter implements CallbackFilter {
private final AdvisedSupport advised;
private final Map<String, Integer> fixedInterceptorMap;
private final int fixedInterceptorOffset;
public ProxyCallbackFilter(AdvisedSupport advised, Map<String, Integer> fixedInterceptorMap, int fixedInterceptorOffset) {
this.advised = advised;
this.fixedInterceptorMap = fixedInterceptorMap;
this.fixedInterceptorOffset = fixedInterceptorOffset;
}
/**
* Implementation of CallbackFilter.accept() to return the index of the
* callback we need.
* <p>The callbacks for each proxy are built up of a set of fixed callbacks
* for general use and then a set of callbacks that are specific to a method
* for use on static targets with a fixed advice chain.
* <p>The callback used is determined thus:
* <dl>
* <dt>For exposed proxies</dt>
* <dd>Exposing the proxy requires code to execute before and after the
* method/chain invocation. This means we must use
* DynamicAdvisedInterceptor, since all other interceptors can avoid the
* need for a try/catch block</dd>
* <dt>For Object.finalize():</dt>
* <dd>No override for this method is used.</dd>
* <dt>For equals():</dt>
* <dd>The EqualsInterceptor is used to redirect equals() calls to a
* special handler to this proxy.</dd>
* <dt>For methods on the Advised class:</dt>
* <dd>the AdvisedDispatcher is used to dispatch the call directly to
* the target</dd>
* <dt>For advised methods:</dt>
* <dd>If the target is static and the advice chain is frozen then a
* FixedChainStaticTargetInterceptor specific to the method is used to
* invoke the advice chain. Otherwise a DyanmicAdvisedInterceptor is
* used.</dd>
* <dt>For non-advised methods:</dt>
* <dd>Where it can be determined that the method will not return {@code this}
* or when {@code ProxyFactory.getExposeProxy()} returns {@code false},
* then a Dispatcher is used. For static targets, the StaticDispatcher is used;
* and for dynamic targets, a DynamicUnadvisedInterceptor is used.
* If it possible for the method to return {@code this} then a
* StaticUnadvisedInterceptor is used for static targets - the
* DynamicUnadvisedInterceptor already considers this.</dd>
* </dl>
*/
@Override
public int accept(Method method) {
if (AopUtils.isFinalizeMethod(method)) {
logger.debug("Found finalize() method - using NO_OVERRIDE");
return NO_OVERRIDE;
}
if (!this.advised.isOpaque() && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
if (logger.isDebugEnabled()) {
logger.debug("Method is declared on Advised interface: " + method);
}
return DISPATCH_ADVISED;
}
// We must always proxy equals, to direct calls to this.
if (AopUtils.isEqualsMethod(method)) {
logger.debug("Found 'equals' method: " + method);
return INVOKE_EQUALS;
}
// We must always calculate hashCode based on the proxy.
if (AopUtils.isHashCodeMethod(method)) {
logger.debug("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.isDebugEnabled()) {
logger.debug("Must expose proxy on advised method: " + method);
}
return AOP_PROXY;
}
String key = method.toString();
// Check to see if we have fixed interceptor to serve this method.
// Else use the AOP_PROXY.
if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(key)) {
if (logger.isDebugEnabled()) {
logger.debug("Method has advice and optimisations are enabled: " + method);
}
// We know that we are optimising so we can use the FixedStaticChainInterceptors.
int index = this.fixedInterceptorMap.get(key);
return (index + this.fixedInterceptorOffset);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Unable to apply any optimisations to advised method: " + method);
}
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
// cannot use a dispatcher because the target cannot be released.
if (exposeProxy || !isStatic) {
return INVOKE_TARGET;
}
Class<?> returnType = method.getReturnType();
if (targetClass == returnType) {
if (logger.isDebugEnabled()) {
logger.debug("Method " + method +
"has return type same as target type (may return this) - using INVOKE_TARGET");
}
return INVOKE_TARGET;
}
else if (returnType.isPrimitive() || !returnType.isAssignableFrom(targetClass)) {
if (logger.isDebugEnabled()) {
logger.debug("Method " + method +
" has return type that ensures this cannot be returned- using DISPATCH_TARGET");
}
return DISPATCH_TARGET;
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Method " + method +
"has return type that is assignable from the target type (may return this) - " +
"using INVOKE_TARGET");
}
return INVOKE_TARGET;
}
}
}
ProxyFactoryBean
上面介绍了ProcyFactory获取代理对象的主要逻辑,在介绍引介增强时,我们还使用到了ProxyFactoryBean,这里我们来看下ProxyFactoryBean里面的处理逻辑。
ProxyFactoryBean实现了FactoryBean,是一个工厂bean,工厂bean获取对象的方式是通过重写的getObject()来返回的,所以我们直接去看ProxyFactoryBean的getObject()方法:
ProxyFactoryBean#getObject:
public Object getObject() throws BeansException {
initializeAdvisorChain();
if (isSingleton()) {
return getSingletonInstance();
}
else {
if (this.targetName == null) {
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance();
}
}
这里的逻辑主要有两部分:一个是处理增强链initializeAdvisorChain,还有就是获取代理对象getInstance。
initializeAdvisorChain
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
//省略部分代码
// Globals can't be last unless we specified a targetSource using the property...
if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
throw new AopConfigException("Target required after globals");
}
// Materialize interceptor chain from bean names.
for (String name : this.interceptorNames)
else {
// If we get here, we need to add a named interceptor.
// We must check if it's a singleton or prototype.
Object advice;
if (this.singleton || this.beanFactory.isSingleton(name)) {
// Add the real Advisor/Advice to the chain.
advice = this.beanFactory.getBean(name);
}
else {
// It's a prototype Advice or Advisor: replace with a prototype.
// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
advice = new PrototypePlaceholderAdvisor(name);
}
addAdvisorOnChainCreation(advice, name);
}
}
}
this.advisorChainInitialized = true;
}
private void addAdvisorOnChainCreation(Object next, String name) {
// We need to convert to an Advisor if necessary so that our source reference
// matches what we find from superclass interceptors.
Advisor advisor = namedBeanToAdvisor(next);
if (logger.isTraceEnabled()) {
logger.trace("Adding advisor with name '" + name + "'");
}
addAdvisor(advisor);
}
/**
* List of Advisors. If an Advice is added, it will be wrapped
* in an Advisor before being added to this List.
*/
private List<Advisor> advisors = new LinkedList<Advisor>();
还记得我们使用ProxyFactoryBean时的参数么:
<bean id="target" class="com.ljw.testSpringMode.aop.advice.Trumpet"></bean>
<bean id="introduction" class="com.ljw.testSpringMode.aop.advice.MonitorIntroduction"/>
<bean id="trumpet" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.ljw.testSpringMode.aop.advice.MonitorAccess"
p:interceptorNames="introduction"
p:target-ref="target"
p:proxyTargetClass="true"
/>
我们的interceptorNames参数就是在这个里面使用到,根据这些id,直接获取对应的bean对象,最后使用一个list维护这些增强。
getInstance
处理完了增强链以后,接着根据bean的类型返回对应的代理示例:
if (isSingleton()) {
return getSingletonInstance();
}
else {
if (this.targetName == null) {
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance();
}
我们这里关注下单例的场景:
private synchronized Object getSingletonInstance() {
if (this.singletonInstance == null) {
this.targetSource = freshTargetSource();
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
// Rely on AOP infrastructure to tell us what interfaces to proxy.
Class<?> targetClass = getTargetClass();
if (targetClass == null) {
throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
}
setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
}
// Initialize the shared singleton instance.
super.setFrozen(this.freezeProxy);
this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;
}
这里我们看到了一个熟悉的方法getProxy(),哦,原来ProxyFactoryBean内部获取代理示例的逻辑和FactoryBean是一样的,只不过它利用factoryBean的特性对增强链进行了维护。
总结
Spring Aop生成代理对象主要有两种方式:jdk和cglib,前者通过反射实现,只能针对接口类,后者通过cglib动态生成子类实现,无法对private 和 final修饰的内容进行代理,Spring AOP的代理级别是方法级别。
欢迎扫码一起交流学习
以上是关于源码学习之AOP-代理对象的生成的主要内容,如果未能解决你的问题,请参考以下文章
Spring读源码系列之AOP--06---AopProxy===>spring使用jdk和cglib生成代理对象的终极奥义
框架学习之Spring----AOP and jdbcTemplate