zoukankan      html  css  js  c++  java
  • 方法接口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源码学习之路就圆满结束了,虽说时光不长,但收成甚大。各位如果有兴致,相信当初也完全有能力自己去看源码了,以后有问题,不要找度娘了,找源码吧。

        

        


        

        

        

    文章结束给大家分享下程序员的一些笑话语录: 刹车失灵
    有一个物理学家,工程师和一个程序员驾驶着一辆汽车行驶在阿尔卑斯山脉 上,在下山的时候,忽然,汽车的刹车失灵了,汽车无法控制地向下冲去, 眼看前面就是一个悬崖峭壁,但是很幸运的是在这个悬崖的前面有一些小树 让他们的汽车停了下来, 而没有掉下山去。 三个惊魂未定地从车里爬了出来。
    物理学家说, “我觉得我们应该建立一个模型来模拟在下山过程中刹车片在高 温情况下失灵的情形”。
    工程师说, “我在车的后备厢来有个扳手, 要不我们把车拆开看看到底是什么 原因”。
    程序员说,“为什么我们不找个相同的车再来一次以重现这个问题呢?”

    --------------------------------- 原创文章 By 方法和接口 ---------------------------------

  • 相关阅读:
    实践测试登录功能的思路与原理解析(基于 Spring Security)
    测试人如何突破职业瓶颈,实现指数级成长?| 测试大咖在线沙龙
    往期优秀文章
    webRTC初接触,网页获取媒体音视频
    Guava Cache源码浅析
    打着维护用户利益旗号的厮杀
    HDFS资源管理器源码发布
    Ext复制grid里某一列的值
    不引入外部文件也可以显示图片
    页面嵌入Windows Media Player需要注意的
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3095549.html
Copyright © 2011-2022 走看看