spring源码学习之路---深入AOP(终)

本文内容纲要:spring源码学习之路---深入AOP(终)

作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可。

上一章和各位一起看了一下springAOP的工作流程,当我们给出AOP相关的配置以后,直接从IOC容器中拿出来的就是已经加强过的bean。这说明spring在这个过程中一定做了什么。

本章我们就一起来看一下spring是如何完成对bean的增强的,首先我们来看一下,FactoryBean接口中一个方法的定义。

public interface FactoryBean<T> {

/**

* Return an instance (possibly shared or independent) of the object

* managed by this factory.

* <p>As with a {@link BeanFactory}, this allows support for both the

* Singleton and Prototype design pattern.

* <p>If this FactoryBean is not fully initialized yet at the time of

* the call (for example because it is involved in a circular reference),

* throw a corresponding {@link FactoryBeanNotInitializedException}.

* <p>As of Spring 2.0, FactoryBeans are allowed to return <code>null</code>

* objects. The factory will consider this as normal value to be used; it

* will not throw a FactoryBeanNotInitializedException in this case anymore.

* FactoryBean implementations are encouraged to throw

* FactoryBeanNotInitializedException themselves now, as appropriate.

* @return an instance of the bean (can be <code>null</code>)

* @throws Exception in case of creation errors

* @see FactoryBeanNotInitializedException

*/

T getObject() throws Exception;

getObject这个方法,就是用来获取被这个factorybean加强后的对象的,上一章测试的过程中,最终就是调用了这个方法,来完成了对bean的加强。我们来跟踪一下上一次测试的代码,看看到底是在什么地方调用的。这里再次贴出来上次测试的代码,方便解释。

public class TestAOP {

public static void main(String[] args) {

ApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:beans.xml");

TestTarget target = (TestTarget) applicationContext.getBean("testAOP");

target.test();

System.out.println("------无敌分割线-----");

target.test2();

}

}

其实整个过程也就两行代码,第一行代码,是我们对IOC容器的初始化,这时其实并没有发生对bean的增强,原因就是这个时候只是完成了对ProxyFactoryBean的初始化,也就是相当于我们已经new出来了一个ProxyFactoryBean,但是此时并没有调用接口方法,去获得加强后的bean。

下面我们去跟进第二行获取testAOP的代码,来看一下究竟。首先我们会找到AbstractApplicationContext中的getBean方法,但是这个类并不负责bean的实例化工作,而是交给了bean工厂,我们跟踪bean工厂的方法,能找到上述第二行其实是调用了如下这个方法。

@SuppressWarnings("unchecked")

protected <T> T doGetBean(

final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)

throws BeansException {

final String beanName = transformedBeanName(name);

Object bean;

// Eagerly check singleton cache for manually registered singletons.

Object sharedInstance = getSingleton(beanName);

if (sharedInstance != null && args == null) {

if (logger.isDebugEnabled()) {

if (isSingletonCurrentlyInCreation(beanName)) {

logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +

"' that is not fully initialized yet - a consequence of a circular reference");

}

else {

logger.debug("Returning cached instance of singleton bean '" + beanName + "'");

}

}

bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);

}

else {

// Fail if we're already creating this bean instance:

// We're assumably within a circular reference.

if (isPrototypeCurrentlyInCreation(beanName)) {

throw new BeanCurrentlyInCreationException(beanName);

}

// Check if bean definition exists in this factory.

BeanFactory parentBeanFactory = getParentBeanFactory();

if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {

// Not found -> check parent.

String nameToLookup = originalBeanName(name);

if (args != null) {

// Delegation to parent with explicit args.

return (T) parentBeanFactory.getBean(nameToLookup, args);

}

else {

// No args -> delegate to standard getBean method.

return parentBeanFactory.getBean(nameToLookup, requiredType);

}

}

if (!typeCheckOnly) {

markBeanAsCreated(beanName);

}

final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

checkMergedBeanDefinition(mbd, beanName, args);

// Guarantee initialization of beans that the current bean depends on.

String[] dependsOn = mbd.getDependsOn();

if (dependsOn != null) {

for (String dependsOnBean : dependsOn) {

getBean(dependsOnBean);

registerDependentBean(dependsOnBean, beanName);

}

}

// Create bean instance.

if (mbd.isSingleton()) {

sharedInstance = getSingleton(beanName, new ObjectFactory() {

public Object getObject() throws BeansException {

try {

return createBean(beanName, mbd, args);

}

catch (BeansException ex) {

// Explicitly remove instance from singleton cache: It might have been put there

// eagerly by the creation process, to allow for circular reference resolution.

// Also remove any beans that received a temporary reference to the bean.

destroySingleton(beanName);

throw ex;

}

}

});

bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

}

else if (mbd.isPrototype()) {

// It's a prototype -> create a new instance.

Object prototypeInstance = null;

try {

beforePrototypeCreation(beanName);

prototypeInstance = createBean(beanName, mbd, args);

}

finally {

afterPrototypeCreation(beanName);

}

bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);

}

else {

String scopeName = mbd.getScope();

final Scope scope = this.scopes.get(scopeName);

if (scope == null) {

throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");

}

try {

Object scopedInstance = scope.get(beanName, new ObjectFactory() {

public Object getObject() throws BeansException {

beforePrototypeCreation(beanName);

try {

return createBean(beanName, mbd, args);

}

finally {

afterPrototypeCreation(beanName);

}

}

});

bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);

}

catch (IllegalStateException ex) {

throw new BeanCreationException(beanName,

"Scope '" + scopeName + "' is not active for the current thread; " +

"consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",

ex);

}

}

}

// Check if required type matches the type of the actual bean instance.

if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {

throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());

}

return (T) bean;

}

这是一个重载方法,后面三个参数两个为null,一个为false。下面注意,在这面这一行的时候,我们已经获取到了实例。

Object sharedInstance = getSingleton(beanName);

所以分支在碰到第一个if判断时,会直接进入if块而不是else块,在这里提醒一下,这个是获取的单例的bean实例,而这个sharedInstance并不是TestTarget,而是ProxyFactoryBean的实例。好了,接下来相信你已经明白了,我们该进入getObjectForBeanInstance这个方法了,来看这个方法。

protected Object getObjectForBeanInstance(

Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {

// Don't let calling code try to dereference the factory if the bean isn't a factory.

if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {

throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());

}

// Now we have the bean instance, which may be a normal bean or a FactoryBean.

// If it's a FactoryBean, we use it to create a bean instance, unless the

// caller actually wants a reference to the factory.

if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {

return beanInstance;

}

Object object = null;

if (mbd == null) {

object = getCachedObjectForFactoryBean(beanName);

}

if (object == null) {

// Return bean instance from factory.

FactoryBean factory = (FactoryBean) beanInstance;

// Caches object obtained from FactoryBean if it is a singleton.

if (mbd == null && containsBeanDefinition(beanName)) {

mbd = getMergedLocalBeanDefinition(beanName);

}

boolean synthetic = (mbd != null && mbd.isSynthetic());

object = getObjectFromFactoryBean(factory, beanName, !synthetic);

}

return object;

}

方法的刚开始是两个卫语句,第一个判断如果是想获得factorybean本身,却又不是factorybean则抛出异常,第二个则是正常的获得factorybean。但是我们都不属于这两种情况。所以在经过getCachedObjectForFactoryBean获取无果和getCachedObjectForFactoryBean获取到bean定义以后,就进入了getObjectFromFactoryBean方法。

protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess) {

if (factory.isSingleton() && containsSingleton(beanName)) {

synchronized (getSingletonMutex()) {

Object object = this.factoryBeanObjectCache.get(beanName);

if (object == null) {

object = doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);

this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));

}

return (object != NULL_OBJECT ? object : null);

}

}

else {

return doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);

}

}

进入以后,由于proxyFactorybean是单例bean,所以会进入到if块不是else块,接下来系统再次尝试从cache中获得,自然是无果。接下来依然会进入到和else一样的方法doGetObjectFromFactoryBean,先不说这个方法,看后面,获得以后就会放入cache,然后直接将对象返回。所以如果重复调用,下一次就会从cache当中取出来直接返回。好了,接下来我们进去doGetObjectFromFactoryBean方法。

private Object doGetObjectFromFactoryBean(

final FactoryBean factory, final String beanName, final boolean shouldPostProcess)

throws BeanCreationException {

Object object;

try {

if (System.getSecurityManager() != null) {

AccessControlContext acc = getAccessControlContext();

try {

object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {

public Object run() throws Exception {

return factory.getObject();

}

}, acc);

}

catch (PrivilegedActionException pae) {

throw pae.getException();

}

}

else {

object = factory.getObject();

}

}

catch (FactoryBeanNotInitializedException ex) {

throw new BeanCurrentlyInCreationException(beanName, ex.toString());

}

catch (Throwable ex) {

throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);

}

// Do not accept a null value for a FactoryBean that's not fully

// initialized yet: Many FactoryBeans just return null then.

if (object == null && isSingletonCurrentlyInCreation(beanName)) {

throw new BeanCurrentlyInCreationException(

beanName, "FactoryBean which is currently in creation returned null from getObject");

}

if (object != null && shouldPostProcess) {

try {

object = postProcessObjectFromFactoryBean(object, beanName);

}

catch (Throwable ex) {

throw new BeanCreationException(beanName, "Post-processing of the FactoryBean's object failed", ex);

}

}

return object;

}

此处判断了一下当前是否设置了安全管理器,我们并没有设置,所以将直接调用ProxyFactoryBean的getObject方法,也就是对bean增强的地方。下面我们着重来看一下是如何对bean进行增强的。首先我们进入到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();

}

}

此处主要是先初始化了一下通知器链,然后就会根据是否单例做相应的动作,我们看一下初始化通知器链的进行。

private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {

if (this.advisorChainInitialized) {

return;

}

if (!ObjectUtils.isEmpty(this.interceptorNames)) {

if (this.beanFactory == null) {

throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +

"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));

}

// 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) {

if (logger.isTraceEnabled()) {

logger.trace("Configuring advisor or advice '" + name + "'");

}

if (name.endsWith(GLOBAL_SUFFIX)) {

if (!(this.beanFactory instanceof ListableBeanFactory)) {

throw new AopConfigException(

"Can only use global advisors or interceptors with a ListableBeanFactory");

}

addGlobalAdvisor((ListableBeanFactory) this.beanFactory,

name.substring(0, name.length() - GLOBAL_SUFFIX.length()));

}

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;

}

可以看到,其中针对我们配置的interpretorNames进行了循环,我们并非是配置的全局通知器,所以会进入else块,然后因为我们配置的testAdvisor默认是单例的,所以会从bean工厂中去获取这个实例,此时TestAdvisor已经实例化完成的,我们只是去取一下而已。然后就会进入addAdvisorOnChainCreation方法。这个方法不再一一贴进来,各位有兴趣的可以自己去看一下,就是把通知器加到了通知链当中。

值得注意的是在这个过程中,触发了一个这样的方法this.advisorAdapterRegistry.wrap(next)。这个方法就是用来包装通知器的,如果不是advisor而是advice,就会包装一下返回。

好了,接着刚才的过程,初始化通知器链完成以后,就会进入getSingletonInstance方法,这是用来获取单例实例的,而真正的加强也是在这里发生的,我们来看一下。

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;

}

此时第一次获取,单例实例为null,所以会进入if块,首先刷新targetSource,因为我们的Target类没有实现targetSource接口,所以会由spring帮我们产生一个targetSource适配,这里是使用的适配器的模式,有兴趣可以进去看一下,我们此处不关注这个。接下来,会去判断代理接口,并且设置代理接口,但是我们的target未实现任何接口,所以此处interfaces仍然为空的,所以最后一步createAopProxy时,会帮我们创建cglib的proxy。最终由cglib生成代理返回。

执行下国际惯例,说完以后总要稍微总结一下,主要说几点:

1.在IOC容器初始化的过程中,并没有发生增强的动作,而是初始化了proxyFactoryBean。

2.如果配置中不指定,所有bean默认都是单例和非延迟加载的,也就是说所有的bean都将在第一次IOC容器初始化时全部实例化,所以上一章中所配置的三个bean都是在IOC容器初始化时进行的实例化。

3.springAOP代理有两种方式,一种是JDK提供的动态代理,一种是cglib字节码生成的技术,当要代理的类有实现的接口的时候,就会针对接口进行代理,否则就会采用cglib直接生成字节码产生子类。

到此处,我们已经基本上完全跟了一遍整个bean增强的过程,也大概了解了springAOP的大概原理,相信各位心中应该有个大概的印象了,其实springAOP增强的原理已经浮现出来了,接下来再研究下去,可能会收获甚微,还是要结合平时的应用和自己的兴趣去体会,始终不赞同一头扎进去就埋头苦干的作风。

好了,spring源码学习之路就圆满结束了,虽说时间不长,但收获甚大。各位如果有兴趣,相信现在也完全有能力自己去看源码了,以后有问题,不要找度娘了,找源码吧。

本文内容总结:spring源码学习之路---深入AOP(终)

原文链接:https://www.cnblogs.com/zuoxiaolong/p/spring7.html

以上是 spring源码学习之路---深入AOP(终) 的全部内容, 来源链接: utcz.com/z/362941.html

回到顶部