springmvc和spring整合中不用注入,而通过获取父子容器再获取bean的方法。

一般在ssm项目中使用注解来注入属性值较为方便。这里说如何通过获取父子容器再通过getBean("")来拿到对象的方法。

首先定义子父容器

(1)spring是一个大的父容器,springmvc是其中的一个子容器。父容器不能访问子容器对象,但是子容器可以访问父容器对象。 

(2)一般做一个ssm框架项目的时候,扫描@controller注解类的对象是在springmvc容器中。而扫描@service、@component、@Repository等注解类的对象都是在spring容器中。

父容器对应这个配置,在Application监听器中创建一个父容器,把service,dao层的对象引用全部存在这容器,根据后面classpath:spring/applicationContext-*.xml配置文件的扫描配置<context:component-scan base-package="service,entity"/>。

<!-- 加载spring容器 -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring/applicationContext-*.xml</param-value>
	</context-param>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

子容器对应这个配置,把controller层的对象引用全部存在这容器,也根据springmvc的扫描配置。

<!-- springmvc的前端控制器 -->
	<servlet>
		<servlet-name>MyServletName</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<!-- contextConfigLocation不是必须的, 如果不配置contextConfigLocation, springmvc的配置文件默认在:WEB-INF/servlet的name+"-servlet.xml" -->
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:spring/springmvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

 

但是两个容器随着tomcat服务器启动,并创建后存在哪里呢?

通过找到ContextLoader.initWebApplicationContext( )可以发现他存在ServletContext对象存了一份,又在ContextLoader中存了一份。并且String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";

	/**
	 * Initialize Spring's web application context for the given servlet context,
	 * using the application context provided at construction time, or creating a new one
	 * according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
	 * "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
	 * @param servletContext current servlet context
	 * @return the new WebApplicationContext
	 * @see #ContextLoader(WebApplicationContext)
	 * @see #CONTEXT_CLASS_PARAM
	 * @see #CONFIG_LOCATION_PARAM
	 */
	public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
		if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
			throw new IllegalStateException(
					"Cannot initialize context because there is already a root application context present - " +
					"check whether you have multiple ContextLoader* definitions in your web.xml!");
		}

		Log logger = LogFactory.getLog(ContextLoader.class);
		servletContext.log("Initializing Spring root WebApplicationContext");
		if (logger.isInfoEnabled()) {
			logger.info("Root WebApplicationContext: initialization started");
		}
		long startTime = System.currentTimeMillis();

		try {
			// Store context in local instance variable, to guarantee that
			// it is available on ServletContext shutdown.
			if (this.context == null) {
				this.context = createWebApplicationContext(servletContext);
			}
			if (this.context instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
				if (!cwac.isActive()) {
					// The context has not yet been refreshed -> provide services such as
					// setting the parent context, setting the application context id, etc
					if (cwac.getParent() == null) {
						// The context instance was injected without an explicit parent ->
						// determine parent for root web application context, if any.
						ApplicationContext parent = loadParentContext(servletContext);
						cwac.setParent(parent);
					}
					configureAndRefreshWebApplicationContext(cwac, servletContext);
				}
			}
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

			ClassLoader ccl = Thread.currentThread().getContextClassLoader();
			if (ccl == ContextLoader.class.getClassLoader()) {
				currentContext = this.context;
			}
......

在springmvc的入口Servlet DispatcherServlet中没找到创建子容器的方法,查他的父类FrameworkServlet中找到initWebApplicationContext() 方法创建子容器。容易发现代码中也把子容器在ServletContext中存了一份,getServletContext().setAttribute(attrName, wac);其中attrName=SERVLET_CONTEXT_PREFIX + getServletName();

public static final String SERVLET_CONTEXT_PREFIX = FrameworkServlet.class.getName() + ".CONTEXT."

protected WebApplicationContext initWebApplicationContext() {
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;

		if (this.webApplicationContext != null) {
			// A context instance was injected at construction time -> use it
			wac = this.webApplicationContext;
			if (wac instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
				if (!cwac.isActive()) {
					// The context has not yet been refreshed -> provide services such as
					// setting the parent context, setting the application context id, etc
					if (cwac.getParent() == null) {
						// The context instance was injected without an explicit parent -> set
						// the root application context (if any; may be null) as the parent
						cwac.setParent(rootContext);
					}
					configureAndRefreshWebApplicationContext(cwac);
				}
			}
		}
		if (wac == null) {
			// No context instance was injected at construction time -> see if one
			// has been registered in the servlet context. If one exists, it is assumed
			// that the parent context (if any) has already been set and that the
			// user has performed any initialization such as setting the context id
			wac = findWebApplicationContext();
		}
		if (wac == null) {
			// No context instance is defined for this servlet -> create a local one
			wac = createWebApplicationContext(rootContext);
		}

		if (!this.refreshEventReceived) {
			// Either the context is not a ConfigurableApplicationContext with refresh
			// support or the context injected at construction time had already been
			// refreshed -> trigger initial onRefresh manually here.
			onRefresh(wac);
		}

		if (this.publishContext) {
			// Publish the context as a servlet context attribute.
			String attrName = getServletContextAttributeName();
			getServletContext().setAttribute(attrName, wac);
			if (this.logger.isDebugEnabled()) {
				this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
						"' as ServletContext attribute with name [" + attrName + "]");
			}
		}

		return wac;
	}

 

这样就能从ServletContext的属性map中找到这两个容器了,key值如上所述。以下是实验(@service默认名是类名第一个字母改成小写)。

	@RequestMapping("/select/{cid}")
	public String showPage(HttpServletRequest request,@PathVariable int cid){
		ServletContext sc = request.getSession().getServletContext();
		WebApplicationContext fu= ContextLoader.getCurrentWebApplicationContext();//父容器
		Object bean = fu.getBean("country1");
		//Object bean2 = fu.getBean("pageController");//父容器不能访问子容器controller放在spingmvc容器中(子容器)
		//子容器,MyServletName不同,第二个参数不加则获取父容器
		WebApplicationContext zi = WebApplicationContextUtils.getWebApplicationContext(sc,"org.springframework.web.servlet.FrameworkServlet.CONTEXT.MyServletName");
		Object bean2 = zi.getBean("pageController");
		Object bean3 = fu.getBean("countryService");
		System.out.println(zi.hashCode());
		System.out.println(fu.hashCode());
		System.out.println((Country)bean);
		System.out.println(bean2);
		System.out.println(bean3);
		return "index";
	}

输出值:

3113088
22818126
Country [cid=123, cname=sgg]
controller.PageController@10618e1
service.CountryService@13a6137

 

总结:spring把对象交给了容器管理。通俗讲就是:根据配置文件,或者根据注解,spring框架自动完成了对象的创建,并把这些对象的引用在一个容器中存了一份。(注解只能对应一个对象,xml里可以配置多个对象。)如果想在普通函数中(非注入方式)拿到对象,就要先拿到容器,容器又在ServletContext中存了一份。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值