SpringBeanAutowiringSupport介绍

spring-web在version2.5.1的时候,在package org.springframework.web.context.support下加入了一个工具类叫SpringBeanAutowiringSupport,主要用来对Spring Web Application Context之外的类提供@Autowired注入功能。

官方Doc讲的更清楚点:
http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/context/support/SpringBeanAutowiringSupport.html
引用
Convenient base class for self-autowiring classes that gets constructed within a Spring-based web application. Resolves @Autowired annotations in the endpoint class against beans in the current Spring root web application context (as determined by the current thread's context ClassLoader, which needs to be the web application's ClassLoader). Can alternatively be used as a delegate instead of as a base class.


具体来讲,Servlet中本来不能使用@Autowired注入bean,解决办法是在Servlet的init(ServletConfig)方法中调用SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this),就可以直接使用@Autowired来注入Web Application Context下的一些Service等Bean了。(见下例)

又或者使用Quartz Job的时候,可以在Job类中使用SpringBeanAutowiringSupport,就可以直接直使Spring的bean了。(当然如果Job比较多的话,这种方法还是很不方便,推荐使用SchedulerFactoryBean来集成。另一种更方便的办法是直接将Job集成到Spring Context中,当做一个bean)。

值得注意的是,这个类的作用域是Web Application Context,如果应用中实现的是一个比如ConfigurableApplicationContext,那就不能用该方法来对Servlet或是Job或是其它目标类提供@Autowired。

1. 例子:在Servlet中使用:
public class InitServlet extends HttpServlet {
       
	@Autowired
	private ServiceA serviceA;
    
    public void init(ServletConfig config) throws ServletException {
		super.init(config);
		SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
		assertNotNull("Service should be injected.", serviceA);
    }
    
		// Omitted doGet(req, res), doPost(req, res);
}


2. 例子:在Quartz Job中使用:
public class DumpJob implements Job {
	
	@Autowired
	private ServiceA serviceA;

	public void execute(JobExecutionContext context) throws JobExecutionException {
		SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
        assertNotNull("Service should be injected.", serviceA);
	}
}


3. SpringBeanAutowiringSupport源码分析:
/**
	 * Process {@code @Autowired} injection for the given target object,
	 * based on the current web application context.
	 * <p>Intended for use as a delegate.
	 * @param target the target object to process
	 * @see org.springframework.web.context.ContextLoader#getCurrentWebApplicationContext()
	 */
	public static void processInjectionBasedOnCurrentContext(Object target) {
		Assert.notNull(target, "Target object must not be null");
		WebApplicationContext cc = ContextLoader.getCurrentWebApplicationContext();
		if (cc != null) {
			AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
			bpp.setBeanFactory(cc.getAutowireCapableBeanFactory());
			bpp.processInjection(target);
		}
		else {
			if (logger.isDebugEnabled()) {
				logger.debug("Current WebApplicationContext is not available for processing of " +
						ClassUtils.getShortName(target.getClass()) + ": " +
						"Make sure this class gets constructed in a Spring web application. Proceeding without injection.");
			}
		}
	}

从方法第2行可以看出通过ContextLoader拿到当前的WebApplicationContext对象,再通过AutowiredAnnotationBeanPostProcessor类来解决当前传入的目标class的@Autowired注入能力。
(AutowiredAnnotationBeanPostProcessor在Spring2.5随着Annotation功能的扩展而增加的,我们平时用context namepace的标签<context:component-scan>时,Spring会默认生成注册AutowiredAnnotationBeanPostProcessor类来帮助解析@Autowired @Value @Inject等标签。)

4. 使用另一个工具类WebApplicationContextUtils来获取Service Bean:
WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(config.getServletContext());
ServiceA ServiceA = context.getBean(ServiceA.class);

当然这个方法更强大,因为直接拿到WebApplicationContext对象了!

5. 补充WebApplicationContext相关:
对于Web项目,通常使用org.springframework.web.context.ContextLoaderListener,设置属性contextConfigLocation来生成WebApplicationContext。

WebApplicationContext类图(用StarUML画的):

猜你喜欢

转载自angelbill3.iteye.com/blog/2371756