spring项目xml配置,spring加载过程

关于使用DispatcherServlet加载spring流程中,binFactory 的设置
 

1

2

3

initWebApplicationContext() -> createWebApplicationContext() -> createWebApplicationContext() -> configureAndRefreshWebApplicationContext() -> <br>wac.refresh() (wac为ConfigurableWebApplicationContext接口,refresh为 AbstractApplicationContext 中方法) ->

此处设置beanFactory

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); -> refreshBeanFactory() (AbstractApplicationContext 的子类  <br>AbstractRefreshableApplicationContext 中重写该方法) 把 beanFactory 放在 private DefaultListableBeanFactory beanFactory;

 
BeanFactoryAware、 BeanNameAware、ApplicationContextAware、ResourceLoaderAware、ServletContextAware

1

2

3

4

5

6

7

8

9

10

11

12

13

14

<context:component-scan base-package="cn.com" /> 扫描代码根路径

@Service

public class UtilsBeanFactoryAware implements BeanFactoryAware{

    private static BeanFactory beanFactory;

    @Override

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {

        this.beanFactory = beanFactory;

    }

    public static Object getBean(String beanName){

        Object object = beanFactory.getBean(beanName);

        return object;

    }

}

获取实例bean:DemoService servie = (DemoService) UtilsBeanFactoryAware.getBean("demoService");

  

通过实现ApplicationContextAware获取spring上下文

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

@Component

public class DynamicBeanUtil implements ApplicationContextAware {

     public static ConfigurableApplicationContext applicationContext;

     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

            this. applicationContext = (ConfigurableApplicationContext)applicationContext ;

     }

     //动态加载spring配置

     public static void loadBeanByXml(String configLocationString) throws GomeFinanceException {

        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader((BeanDefinitionRegistry) getApplicationContext().getAutowireCapableBeanFactory());

//      XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader((BeanDefinitionRegistry) getApplicationContext().getBeanFactory());

//      beanDefinitionReader.setResourceLoader(getApplicationContext());

        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(getApplicationContext()));

        try {           

            beanDefinitionReader.loadBeanDefinitions("/spring/cashier-consumer.xml");

            Object o = getApplicationContext().getBeanFactory().getBean("myBean1");

            logger.info("动态加载dubbo成功");

        catch (BeansException e) {           

            logger.error("动态加载dubbo:BeansException", e);

            throw new GomeFinanceException("动态加载dubbo:BeansException");

        }

     }

}

 

DynamicBeanUtil.loadBeanByXml("file:D://spring-test.xml");//测试

 

XmlWebApplicationContext 中方法(使用DispatcherServlet加载spring流程中,binFactory 的设置) bean的加载,以此为模型设计自己的bean动态加载

@Override

    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {

        // Create a new XmlBeanDefinitionReader for the given BeanFactory.

        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // Configure the bean definition reader with this context's

        // resource loading environment.

        beanDefinitionReader.setEnvironment(this.getEnvironment());

        beanDefinitionReader.setResourceLoader(this);

        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // Allow a subclass to provide custom initialization of the reader,

        // then proceed with actually loading the bean definitions.

        initBeanDefinitionReader(beanDefinitionReader);

        loadBeanDefinitions(beanDefinitionReader);

    }<br>注意:除了通过实现Aware结尾接口获取spring内置对象,也可以通过@Autowired注解直接注入相关对象<br>@Autowired<br>private ApplicationContext applicationContext;


其他Aware接口

1

2

3

4

5

6

7

8

9

10

11

12

@Service("demoService")

public class DemoServiceImpl implements DemoService,BeanNameAware{

    public String sayHello() {

        System.out.println("hello world");

        return "myHellos";

    }

    @Override

    public void setBeanName(String name) {

        System.out.println("DemoServiceImpl实例化  beanId:"+name);//实例化时返回beanId

    }

 

}

1

2

3

4

5

6

7

8

9

@Service

public class UtilsResourceLoaderAware implements ResourceLoaderAware{

    public static ResourceLoader resourceLoader;

    @Override

    public void setResourceLoader(ResourceLoader resourceLoader) {

        this.resourceLoader = resourceLoader;

    }

}

ResourceLoader load= UtilsResourceLoaderAware.resourceLoader;//WebApplicationContext 获取加载器

1

2

3

4

5

6

7

8

9

10

11

在每个JVM中的每个Web Application中,只有一个ServletContext

@Service

public class UtilsServletContextAware implements ServletContextAware{

    public static ServletContext servletContext;

    @Override

    public void setServletContext(ServletContext servletContext) {

        this.servletContext = servletContext;

    }

}

ServletContext sc = request.getServletContext();

ServletContext sc2 = UtilsServletContextAware.servletContext;//获取ServletContext

  

  

  





(1)监听器
ServletContext监听器javax.servlet.ServletContextListener
在Container 加载Web 应用程序时(例如启动 Container 之后),会呼叫contextInitialized() ,而当容器移除Web 应用程序时,会呼叫contextDestroyed () 方法
监听ServletContext对象的生命周期,实际上就是监听Web应用的生命周期
<context-param>
        <param-name>propertiesConfigLocation</param-name>
        <param-value>/props/cashier-web.properties,/props/cashier-error-code.properties</param-value>
</context-param>
<listener>
        <listener-class>cn.com.xmh.frame.listener.PropertiesConfigListener</listener-class>
</listener>
监听器实现类PropertiesConfigListener中获取propertiesConfigLocation
propertiesConfigLocation = sce.getServletContext().getInitParameter("propertiesConfigLocation").trim();
读取配置文件放至 ApplicationCache.getInstance().put(key, value);  通过监听器监听服务启动,加载配置文件到ApplicationCache 自定义缓存类(非spring)
1、org.springframework.web.util.IntrospectorCleanupListener
2、servlet和Filter初始化前和销毁后,都会给实现了servletContextListener接口的监听器发出相应的通知
3、当Servlet容器启动或终止Web应用时,触发ServletContextListener中两个接口

(2)xml文件加载
使用applicationContext.xml文件时是需要在web.xml中添加listener的:
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/applicationContext.xml,/WEB-INF/springmvc-servlet.xml</param-value>
</context-param> 
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
而这个一般是采用非spring mvc架构,如使用struts之类而又想引入spring才添加的,这个是用来加载Application Context。
如果直接采用SpringMVC,只需要把所有相关配置放到xxx-servlet.xml中就OK了

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

<servlet>

    <servlet-name>springmvc</servlet-name>

    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <init-param>

        <param-name>publishContext</param-name>

        <param-value>false</param-value>

    </init-param>

    <init-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>classpath:xxx-servlet.xml</param-value>

    </init-param>

    <load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

    <servlet-name>springmvc</servlet-name>

    <url-pattern>*.dhtml</url-pattern>

    <url-pattern>*.json</url-pattern>

</servlet-mapping>

 


1、ContextLoaderListener实现了ServletContextListener这个接口,所以服务启动后就会执行,ContextLoaderListener中关联了ContextLoader这个类,所以整个加载配置过程由ContextLoader来完成
2、ContextLoader中initWebApplicationContext的过程,方法名称即是其含义。方法中首先创建了WebApplicationContext,配置并且刷新实例化整个SpringApplicationContext中的Bean,放入servletContext中 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);  String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM); 获取xml中contextConfigLocation的属性值
3、ContextLoaderListener类起着至关重要的作用。它读取web.xml中配置的context-param中的配置文件,提前在web容器初始化前准备业务对应的Application context;将创建好的Application context放置于ServletContext中,为springMVC部分的初始化做好准备

容器创建了Servlet实例后,它将调用实例的init(ServletConfig)方法初始化Servlet.该方法的参数ServletConfig对象包含了在WEB应用程序的部署描述文件中指定的初始化参数。在init(ServletConfig)调用完后,容器将调用init()方法,之后Servlet就被初始化了

调用init(ServletConfig config) 进行初始化,ServletConfig封装了web.xml中<init-param>配置的初始化参数,它由Servlet容器创建,并通过该方法传递给当前serlvet 


(3)拦截器
SpringMVC 中的Interceptor拦截器org.springframework.web.servlet.HandlerInterceptor   实现该接口
spring配置文件
<mvc:interceptors>
        <mvc:interceptor>  
            <mvc:mapping path="/**/*"/>
            <bean class="cn.com.xmh.cashier.web.interceptor.CashierUserLoginInterceptor">
                <property name="allowUrls">  
                    <list>  
                        <value>payController/404error.dhtml</value>
                        <value>payController/500error.dhtml</value>
                    </list>  
                </property>
            </bean>
        </mvc:interceptor>
</mvc:interceptors>
拦截器实现类中设置私有变量,preHandle实现该方法
private String[] allowUrls = null;

spring线程池

(4)properties配置文件后置处理
org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
PropertyPlaceholderConfigurer是个bean工厂后置处理器的实现,也就是 BeanFactoryPostProcessor接口的一个实现。PropertyPlaceholderConfigurer可以将上下文(配置文 件)中的属性值放在另一个单独的标准java Properties文件中去。
在XML文件中用${key}替换指定的properties文件中的值。这样的话,只需要对properties文件进 行修改,而不用对xml配置文件进行修改

1

2

3

4

5

6

7

8

<bean id="customPropertyConfigurer" class="cn.com.xmh.cashier.web.util.GroupPropertyPlaceholderConfigurer">

  <property name="ignoreUnresolvablePlaceholders" value="true" />   

  <property name="locations">

    <array> 

        <value>classpath:props/cashier-web.properties</value> 

    </array> 

  </property>

</bean>

继承类GroupPropertyPlaceholderConfigurer中获取配置
Properties mergeProperties = super.mergeProperties();
mergeProperties.put("runtimecashierdubbogroup", group);//“重新”设置配置信息

注释:每台服务器properties文件配置信息一致,根据不同服务来选取配置信息中对应的value(服务地址作为key),比如value为dubbo的group信息

(5)properties配置参数在xml文件中占位符
spring中通过${dubbo.run.redis}来获取.properties文件中dubbo.run.redis的值
<bean id="customPropertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="ignoreUnresolvablePlaceholders" value="true" />    
  <property name="locations">
     <array>  
      <value>classpath:props/cashier-web.properties</value>  
     </array>  
  </property>
</bean>    

 


关于ApplicationContextAware的实现类是如何设置上下文的(包含spring初始化)

1、spring初始化时会调用一下流程

1

2

ApplicationContextAwareProcessor 构造函数中设置ConfigurableApplicationContext最后调用ApplicationContextAware实现类的setApplicationContext方法

(AbstractApplicationContext implements ConfigurableApplicationContext 实际设置的是AbstractApplicationContext)


2、使用DispatcherServlet加载spring

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

DispatcherServlet extends FrameworkServlet extends HttpServletBean extends HttpServlet

HttpServletBean重写了init()方法  通过load-on-startup配置来调用init

FrameworkServlet 重写了initServletBean()被init调用

initServletBean()方法调用 initWebApplicationContext()、initFrameworkServlet()

其中

initWebApplicationContext() -> createWebApplicationContext() -> createWebApplicationContext() -> configureAndRefreshWebApplicationContext() -><br> wac.refresh() (wac为ConfigurableWebApplicationContext接口,refresh为 AbstractApplicationContext 中方法) -> prepareBeanFactory()

-> beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));此时其中的this是 XmlWebApplicationContext <br> 完成ApplicationContextAware的实现类设置上下文

注释:

接口 ConfigurableWebApplicationContext extends WebApplicationContext, ConfigurableApplicationContext

接口 ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable

AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext, DisposableBean

AbstractRefreshableApplicationContext extends AbstractApplicationContext

AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext implements BeanNameAware, InitializingBean

AbstractRefreshableWebApplicationContext extends AbstractRefreshableConfigApplicationContext implements ConfigurableWebApplicationContext, ThemeSource

XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext

 
3、使用ClassPathXmlApplicationContext加载spring

1

2

3

4

5

6

ClassPathXmlApplicationContext 调到父类(AbstractApplicationContext)的refresh() prepareBeanFactory()  <br>beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));此时其中的this是ClassPathXmlApplicationContext   <br>完成ApplicationContextAware的实现类设置上下文

注释:

ClassPathXmlApplicationContext extends AbstractXmlApplicationContext

AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext

AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext implements BeanNameAware, InitializingBean

AbstractRefreshableApplicationContext extends AbstractApplicationContext<br><br>ApplicationContext context = new ClassPathXmlApplicationContext("classpath:my-dubbo-consumer.xml");

 
4、两种加载spring方式关联

1

2

3

4

5

6

7

FrameworkServlet中加载applicationContext

createWebApplicationContext() 方法中 ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

此时contextClass是XmlWebApplicationContext  org.springframework.web.context.support.XmlWebApplicationContext

public static final Class<?> DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;

ContextLoader中加载applicationContext

ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

相同的代码创建上下文

 
5、ApplicationContext 的几种实现
XmlWebApplicationContext
专为web工程定制的方法,推荐Web项目中使用。例如:
ServletContext servletContext = request.getSession().getServletContext();
ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);
FileSystemXmlApplicationContext
这个方法是从文件绝对路径加载配置文件,例如:
ApplicationContext ctx = new FileSystemXmlApplicationContext( "G:/Test/applicationcontext.xml ");
如果在参数中写的不是绝对路径,那么方法调用的时候也会默认用绝对路径来找,我测试的时候发现默认的绝对路径是eclipse所在的路径。
采用绝对路径的话,程序的灵活性就很差了,所以这个方法一般不推荐。(如果要使用classpath路径,需要加入前缀classpath:   )

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不是码农的农民

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值