04_IOC容器装配Bean(xml方式)

IOC容器装配Bean(xml方式)

1.Spring 提供配置Bean三种实例化方式

1)使用类构造器实例化(默认无参数)

  1. <bean id="bean1" class="cn.itcast.spring.b_instance.Bean1"></bean>

2)使用静态工厂方法实例化(简单工厂模式)

  1. //下面这段配置的含义:调用Bean2Factory的getBean2方法得到bean2
  2. <bean id="bean2" class="cn.itcast.spring.b_instance.Bean2Factory" factory-method="getBean2"></bean>

3)使用实例工厂方法实例化(工厂方法模式)

  1. //先创建工厂实例bean3Facory,再通过工厂实例创建目标bean实例
  2. <bean id="bean3Factory" class="cn.itcast.spring.b_instance.Bean3Factory"></bean>
  3. <bean id="bean3" factory-bean="bean3Factory" factory-method="getBean3"></bean>

2.Bean的其它属性配置

<bean>元素的id属性和name属性的区别

早期Spring开发中Bean的 id属性 ,遵守xml语法id约束

* id 的命名要满足XML对ID属性命名规范 必须以字母开始,可以使用字母、数字、连字符、下划线、句话、冒号。

* 使用name属性,就可以使用很多特殊字符,早期在struts1和spring整合 ,如<bean name="/login" class="....LoginAction" />  name中含有/ ,使用id会报错。

**如果元素没有id只有name ,name 属性值可以作为id 使用

<bean>元素scope属性

  1. * scope="singleton" 单例 ,在Spring IoC容器中仅存在一个Bean实例 (默认的scope)
  2. * scope="prototype" 多例 ,每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时 ,相当于执行new XxxBean()
  3. * scope="request" 用于web开发,将Bean放入request范围 ,request.setAttribute("xxx") , 在同一个request 获得同一个Bean
  4. * scope="session" 用于web开发,将Bean 放入Session范围,在同一个Session 获得同一个Bean 
  5. * scope="globalSession" 一般用于Porlet应用环境 , 分布式系统存在全局session概念 ,如果不是porlet环境,globalSession 等同于Session 

在开发中主要使用 scope="singleton"、 scope="prototype"

如果在applicationContext.cfg.xml配置文件中的bean,未指定scope属性,那么默认为singleton

3.Bean的生命周期

1)在配置 <bean> 元素,通过 init-method 指定Bean的初始化方法,通过 destroy-method 指定Bean销毁方法

  1. <beanid="lifeCycleBean"class="cn.itcast.spring.d_lifecycle.LifeCycleBean"init-method="setup"destroy-method="teardown"></bean>

在JavaBean中书写在,<bean>元素里面定义的2个方法setup和teardown

  1. package cn.itcast.spring.d_lifecycle;
  2. publicclassLifeCycleBean{
  3. publicvoid setup(){
  4. System.out.println("初始化...");
  5. }
  6. publicvoid teardown(){
  7. System.out.println("销毁....");
  8. }
  9. }

进行测试:

  1. @Test
  2. // 测试Spring 生命周期
  3. publicvoid demo(){
  4.     ClassPathXmlApplicationContext applicationContext =newClassPathXmlApplicationContext("applicationContext.xml");
  5.     LifeCycleBean lifeCycleBean =(LifeCycleBean) applicationContext.getBean("lifeCycleBean");
  6.     System.out.println(lifeCycleBean);
  7. }

运行结果:

我们发现:运行完程序,销毁方法没有执行。

解析:这个程序运行了,但是Spring容器并不知道何时销毁。

举个例子:例如把一个Spring容器交给tomcat管理时,tomcat停止时,他就会自动调用destroy方法。那么我们就自己来调用这个方法:applicationContext.close();

此时,就会调用销毁方法:

需要注意的问题:

*  destroy-method 只对 scope="singleton" 有效

*  销毁方法,必须关闭ApplicationContext对象(手动调用),才会被调用

  1. ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
  2. applicationContext.close();

2)Bean的完整生命周期 (十一步骤)【了解内容,但是对于spring内部操作理解有一定帮助】

①instantiate bean对象实例化

②populate properties 封装属性

③如果Bean实现BeanNameAware 执行 setBeanName

④如果Bean实现BeanFactoryAware 或者 ApplicationContextAware 设置工厂 setBeanFactory 或者上下文对象 setApplicationContext

⑤如果存在类实现 BeanPostProcessor(后处理Bean) ,执行postProcessBeforeInitialization,BeanPostProcessor接口提供钩子函数,用来动态扩展修改Bean。(程序自动调用后处理Bean)

  1. publicclassMyBeanPostProcessorimplementsBeanPostProcessor{
  2. publicObject postProcessAfterInitialization(Object bean,String beanName)
  3. throwsBeansException{
  4. System.out.println("第八步:后处理Bean,after初始化。");
  5. //后处理Bean,在这里加上一个动态代理,就把这个Bean给修改了。
  6. return bean;//返回bean,表示没有修改,如果使用动态代理,返回代理对象,那么就修改了。
  7. }
  8. publicObject postProcessBeforeInitialization(Object bean,String beanName)
  9. throwsBeansException{
  10. System.out.println("第五步:后处理Bean的:before初始化!!");
  11. //后处理Bean,在这里加上一个动态代理,就把这个Bean给修改了。
  12. return bean;//返回bean本身,表示没有修改。
  13. }
  14. }
  15. 注意:这个前处理Bean和后处理Bean会对所有的Bean进行拦截。

⑥如果Bean实现InitializingBean 执行 afterPropertiesSet

⑦调用<bean init-method="init"> 指定初始化方法 init

⑧如果存在类实现 BeanPostProcessor(处理Bean) ,执行postProcessAfterInitialization

⑨执行业务处理

⑩如果Bean实现 DisposableBean 执行 destroy

?调用<bean destroy-method="customerDestroy"> 指定销毁方法 customerDestroy

* 为了能够比较清晰的看到上面的每一个步骤,我们模拟真实开发场景,定义一个接口和一个实现类

  1. // 用户数据库操作
  2. publicinterfaceUserDAO{
  3. publicvoid add();
  4. publicvoid search();
  5. }

实现类:

  1. // 实现DAO 方法
  2. publicclassUserDAOImplimplementsUserDAO,BeanNameAware,ApplicationContextAware,InitializingBean,DisposableBean{
  3. privateString company;
  4. publicUserDAOImpl(){
  5. System.out.println("第一步 Bean的实例化 ...");
  6. }
  7. // 设置company
  8. publicvoid setCompany(String company){
  9. System.out.println("第二步 设置Bean的属性");
  10. this.company = company;
  11. }
  12. //如果实现了BeanNameAware接口,那么会将bean的那么设置到程序中,也就是userDao
  13. publicvoid setBeanName(String beanName){
  14. System.out.println("第三步 将xml配置Bean的name设置到程序中:"+ beanName);
  15. // <bean id="userDAO" class="cn.itcast.spring.d_lifecycle.UserDAOImpl"></bean>
  16. }
  17. publicvoid setApplicationContext(ApplicationContext applicationContext)throwsBeansException{
  18. System.out.println("第四步 将整合工厂上下文对象设置到 Bean中 ");
  19. }
  20. publicvoid afterPropertiesSet()throwsException{
  21. System.out.println("第六步 属性设置完成后...");
  22. }
  23. publicvoid setup(){
  24. System.out.println("第七步 配置初始化方法...init-method=‘setup‘");
  25. }
  26.  
  27. //Bean初始化完毕,如果有业务方法,那么就开始执行,以下方法模拟业务方法。

  28. //这是在接口中定义的业务操作方法
  29. publicvoid add(){
  30. System.out.println("第九步 业务操作 .... 添加");
  31. }
  32. //这是在接口中定义的业务操作方法
  33. publicvoid search(){
  34. System.out.println("第九步 业务操作 .... 查询");
  35. }
  36.  
  37. //destroy方法必须自己调用closed方法后才会执行。
  38. publicvoid destroy()throwsException{
  39. // 这个destroy无需配置,实现这个接口,就会自动的去调用destroy方法。
  40. System.out.println("第十步 无需配置的销毁方法");
  41. }
  42. publicvoid teardown(){
  43. System.out.println("第十一步 通过配置设置销毁方法...");
  44. }
  45. }

其中少了第五步和第八步,此项内容在上面对应序号位置找。

配置文件applicationContext.cfg.xml:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- 引入约束 来自xsd-config.html文件 -->
  3. <beansxmlns="http://www.springframework.org/schema/beans"
  4. xmlns:p="http://www.springframework.org/schema/p"
  5. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  6. xsi:schemaLocation="
  7. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  8. <beanid="userDAO"class="cn.itcast.spring.d_lifecycle.UserDAOImpl"init-method="setup"destroy-method="teardown">
  9. <!--第二步,设置bean的属性-->
  10. <propertyname="company"value="itcast"></property>
  11. </bean>
  12. <!-- 必须配置后处理Bean , bean没有id 因为由 Spring框架内部调用 -->
  13. <beanclass="cn.itcast.spring.d_lifecycle.MyBeanPostProccessor"></bean>
  14. </beans>

编写测试类:

  1. @Test
  2. // 测试Spring 生命周期
  3. publicvoid demo2(){
  4.     ClassPathXmlApplicationContext applicationContext =newClassPathXmlApplicationContext("applicationContext.xml");
  5.     UserDAO userDAO =(UserDAO) applicationContext.getBean("userDAO");
  6. //执行业务方法
  7.     userDAO.add();
  8.     userDAO.search();
  9.     // 关闭工厂
  10.     applicationContext.close();
  11. }

运行结果:

分析:

前面前处理Bean和后处理Bean被执行多次,表示:钩子函数会对每个bean进行拦截(前面已经配置了其他的几个Bean,每个Bean都执行2次à前处理Bean后处理bean)。故而执行多次,反复连续的输出五,八。

第三步和第四步,使我们写的Bean了解Spring容器

第五步和第八步,使用BeanPostProcessor 就是钩子函数,作用用来对Bean对象进行扩展。

问题: 在userDAO对象所有方法上 添加运行时间监控  【用后处理bean对目标bean在构造时进行代理,对原有方法进行扩展增强!】

我们可以利用后处理bean(BeanPostProcessor)与动态代理一起完成此功能,我们只需要在后处理bean的postProcessAfterInitialization方法里面改动代码即可

  1. /**
  2. * bean 就是对象实例 beanName 就是xml 配置Bean的id 或者 name
  3. */
  4. publicObject postProcessAfterInitialization(finalObject bean,String beanName)throwsBeansException{
  5.     System.out.println("第八步 执行后处理Bean 的初始化完成后方法...");
  6. if(beanName.equals("userDAO")){
  7.     // 需要进行时间监控Bean
  8. Object proxy =Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(),newInvocationHandler(){
  9.     publicObject invoke(Object proxy,Method method,Object[] args)throwsThrowable{
  10.     if(method.getName().equals("search")){
  11.     // 增强search方法
  12. System.out.println("开始时间:"+System.currentTimeMillis());
  13. Object result = method.invoke(bean, args);
  14. System.out.println("结束时间:"+System.currentTimeMillis());
  15. return result;
  16. }else{
  17. // 不加强
  18. return method.invoke(bean, args);
  19. }
  20. }
  21. });
  22. return proxy;
  23. }
  24. return bean;
  25. }

运行测试结果:

我们发现:在业务方法search的前后环绕了增强的功能!

==========================================================================================================================

4.Spring的Bean属性的依赖注入

*spring支持构造器注入和setter方法注入

第一种 构造器注入,通过 <constructor-arg> 元素完成注入

  1. /**
  2. * 轿车 (构造函数注入属性)
  3. */
  4. publicclassCar{
  5. privateString name;
  6. privatedouble price;
  7. publicCar(String name,double price){
  8. super();
  9. this.name = name;
  10. this.price = price;
  11. }
  12. @Override
  13. publicString toString(){
  14. return"Car [name="+ name +", price="+ price +"]";
  15. }
  16. }

配置文件:

  1. <!-- 构造器注入 -->
  2. <beanid="car"class="cn.itcast.spring.e_di.Car">
  3. <!-- 通过构造器参数,完成属性注入 -->
  4. <constructor-argindex="0"type="java.lang.String"value="保时捷"></constructor-arg><!-- 第一个参数 String类型参数 -->
  5. <constructor-argindex="1"type="double"value="1000000"></constructor-arg>
  6. </bean>

第二种 setter方法注入, 通过<property> 元素完成注入  【开发中常用方式】

  1. /**
  2. * 通过setter方法完成属性注入
  3. */
  4. publicclassCar2{
  5. privateString name;
  6. privatedouble price;
  7. // 注入属性时 只需要提供set方法
  8. publicvoid setName(String name){
  9. this.name = name;
  10. }
  11. publicvoid setPrice(double price){
  12. this.price = price;
  13. }
  14. @Override
  15. publicString toString(){
  16. return"Car2 [name="+ name +", price="+ price +"]";
  17. }
  18. }

配置文件:

  1. <!-- setter方法注入 -->
  2. <beanid="car2"class="cn.itcast.spring.e_di.Car2">
  3.     <!-- 通过 property 元素完成属性注入 -->
  4.     <propertyname="name"value="宝马"></property>
  5.     <propertyname="price"value="500000"></property>
  6. </bean>

* 使用 <property> 元素 ref属性,引入另一个Bean对象,完成Bean之间注入

  1. // 员工类
  2. publicclassEmployee{
  3. privateString name;
  4. // 引入Car2对象
  5. privateCar2 car2;
  6. publicvoid setName(String name){
  7. this.name = name;
  8. }
  9. publicvoid setCar2(Car2 car2){
  10. this.car2 = car2;
  11. }
  12. @Override
  13. publicString toString(){
  14. return"Employee [name="+ name +", car2="+ car2 +"]";
  15. }
  16. }

配置文件:

  1. <beanid="employee"class="cn.itcast.spring.e_di.Employee">
  2.     <propertyname="name"value="张三"></property>
  3. <!--ref引用其他Bean的id或者name-->
  4.     <propertyname="car2"ref="car2"></property>
  5. </bean>

* 名称空间 p的使用  (Spring2.5 新特性)

spring2.5版本 引入名称空间p, 简化属性注入的配置

p:<属性名>="xxx" 引入常量值

p:<属性名>-ref="xxx" 引用其它Bean对象

1)引入p名称空间

  1. <beansxmlns="http://www.springframework.org/schema/beans"
  2. xmlns:p="http://www.springframework.org/schema/p"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="
  5. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

2) 改写<property>注入为 p名称空间注入

  1. <bean id="car2" class="cn.itcast.spring.e_di.Car2">
  2.     <!-- 通过 property 元素完成属性注入 -->
  3.     <property name="name" value="宝马"></property>
  4.     <property name="price" value="500000"></property>
  5. </bean>
  6. <bean id="employee" class="cn.itcast.spring.e_di.Employee">
  7.     <property name="name" value="张三"></property>
  8.     <property name="car2" ref="car2"></property> <!-- ref引用其他Bean的id或者name -->
  9. </bean>

改写

  1. <bean id="car2" class="cn.itcast.spring.e_di.Car2" p:name="宝马" p:price="1000000"></bean>
  2. <bean id="employee" class="cn.itcast.spring.e_di.Employee" p:name="李四" p:car2-ref="car2"></bean>

* spring3.0之后引入 spEL 表达式

1) 完成对象之间注入

  1. <property name="car2" ref="car2"></property>

改写为

  1. <property name="car2" value="#{car2}"></property>

2) 使用另一个Bean属性完成注入

  1. // 单独数据Bean
  2. publicclassCarInfo{
  3. publicString getName(){
  4. return"奇瑞QQ";
  5. }
  6. publicdouble caculatePrice(){
  7. return200000;
  8. }
  9. }

配置:

  1. <bean id="carInfo" class="cn.itcast.spring.e_di.CarInfo"></bean>
  1. <bean id="car2_2" class="cn.itcast.spring.e_di.Car2">
  2.     <property name="name" value="#{carInfo.name}"></property>
  3. </bean>

3) 使用另一个Bean方法完成注入

  1. <bean id="carInfo" class="cn.itcast.spring.e_di.CarInfo"></bean>
  2. <bean id="car2_2" class="cn.itcast.spring.e_di.Car2">
  3.     <property name="name" value="#{carInfo.name}"></property>
  4.     <property name="price" value="#{carInfo.caculatePrice()}"></property>
  5. </bean>

5. 集合属性的注入

spring提供专门标签完成 List、Set、Map、Properties 等集合元素属性注入

1) 注入List (数组)

  1. <property name="hobbies">
  2.     <list>
  3.         <!-- <value>注入简单类型,<ref />注入复杂类型 -->
  4.         <value>音乐</value>
  5.         <value>体育</value>
  6.     </list>
  7. </property>

2)  注入Set

  1. <property name="numbers">
  2.     <set>
  3.         <value>10</value>
  4.         <value>6</value>
  5.         <value>15</value>
  6.     </set>
  7. </property>

3) 注入Map

  1. <property name="map">
  2.     <map>
  3.         <!-- 复杂类型<entry key-ref="" value-ref=""></entry> -->
  4.         <entry key="name" value="itcast"></entry>
  5.         <entry key="address" value="北京"></entry>
  6.     </map>
  7. </property>

4)  注入Properties

* java.utils.Properties 类继承 java.utils.HashTable

Properties key和value都是String类型

例如:

  1. <property name="properties">
  2.     <props>
  3.         <prop key="company">传智播客</prop>
  4.         <prop key="pnum">100</prop>
  5.     </props>
  6. </property>

6.在Spring框架中引入多个XML配置文件

第一种 并列引入多个XML

  1. ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans1.xml", "beans2.xml");

第二种 引入总xml文件,在总xml文件引入 子xml文件

  1. ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

* 在applicationContext.xml 中

  1. <import resource="classpath:bean1.xml"/>
  2. <import resource="classpath:bean2.xml"/>

在开发中主要使用第二种 , 将配置文件分离配置,便于维护管理

来自为知笔记(Wiz)

时间: 2024-12-24 14:56:36

04_IOC容器装配Bean(xml方式)的相关文章

JAVAWEB开发之Spring详解之——Spring的入门以及IOC容器装配Bean(xml和注解的方式)、Spring整合web开发、整合Junit4测试

Spring框架学习路线 Spring的IOC Spring的AOP,AspectJ Spring的事务管理,三大框架的整合 Spring框架概述 什么是Spring? Spring是分层的JavaSE/EE full-stack(一站式)轻量级开源框架. 所谓分层: SUN提供的EE的三层结构:web层.业务层.数据访问层(也称持久层,集成层). Struts2是web层基于MVC设计模式框架. Hibernate是持久的一个ORM的框架. 所谓一站式:Spring框架有对三层的每层解决方案.

05_IOC容器装配Bean(注解方式)

IOC容器装配Bean(注解方式) 1.使用注解方式进行Bean注册 xml 方式: <bean id="" class=""> spring2.5版本 提供一组注解,完成Bean注册 * @Component 描述Spring框架中Bean 导入jar 和 xml方式开发是相同的 第一步 编写Class,在声明上 添加 @Component /** * 使用Spring2.5注解 注册Bean */ @Component("helloServ

IOC装配Bean(注解方式)(5)

Spring的注解装配Bean Spring2.5 引入使用注解去定义Bean @Component 描述Spring框架中Bean Spring的框架中提供了与@Component注解等效的三个注解: @Repository 用于对DAO实现类进行标注 @Service 用于对Service实现类进行标注 @Controller 用于对Controller实现类进行标注 ***** 三个注解为了后续版本进行增强的. Bean的属性注入: 普通属性; @Value(value="itcast&q

SpringIOC容器装配Bean

#2019.2.1 Spring 的core Container(Spring的核心容器)有四大部分:bean.context.core.expression 在进行Bean的配置时候,需要添加四个jar包 如下: 分别对应着四大核心部分,最后一个是Apache的日志接口. 在完成添加后,对Spring 的配置文件进行一个最简单的Bean的配置. 1.在项目中添加Source Folder文件(个人习惯) 2.新建一个配置文件.以xml结尾,这里命名为application.xml 3.在配置文

使用 properties 配置文件装配 bean 的方式

在spring中将bean 注册到spring 容器中常见的有三种方式(两类): 先说明配置文件内容:application.yml,有一段配置如下 persons: youtube: name: youtube age: 18 google: name: google age: 20 第一类:将单个类注册到容器中 第一种,使用 @ConfigurationProperties + @Component,配置 GoogleUser @Configuration //效果等同于 @Componen

工作中遇到的问题--缓存配置(使用@Configuration装配 @Bean的方式注入)

@EnableCaching@Configurationpublic class MFGCachingConfiguration { @Autowired private MFGSettings mfgSettings; @Bean(name="MFGKeyGenerator") public KeyGenerator MFGKeyGenerator(){ SimpleKeyGenerator defaultKeyGen = new SimpleKeyGenerator(); KeyG

spring 装配bean的三种方式

这段时间在学习Spring,依赖注入DI和面向切面编程AOP是Spring框架最核心的部分.这次主要是总结依赖注入的bean的装配方式. 什么是依赖注入呢?也可以称为控制反转,简单的来说,一般完成稍微复杂的业务逻辑,可能需要多个类,会出现有些类要引用其他类的实例,也可以称为依赖其他类.传统的方法就是直接引用那个类对象作为自己的一个属性,但如果我们每次创建这个类的对象时,都会创建依赖的类的对象,还有如果那个类将来可能不用了,还需要到这个类去删除这个对象,那破坏了代码的复用性和导致高度耦合! 依赖注

Spring提供的三种装配Bean方式

在Spring中,对象不需要自己查找或创建与其所关联的其他对象,Spring容器负责把需要相互协作的对象引用赋予各个对象.创建应用对象之间协作关系的行为通常称为装配(wiring),这也是依赖注入(DI)的本质. Spring提供了三种主要的装配Bean的方式: 隐式的bean发现和自动化装配 在Java中进行显示配置 在XML中进行显示配置 隐式的bean发现和自动化装配 Spring从两个方面来实现自动化装配: 组件扫描:Spring会自动发现应用上下文中所创建的bean. 自动装配:Spr

装配bean

spring有三种装配bean的方式:隐式装配.java代码装配.xml装配 隐式装配最为省事方便,也称为自动化装配 这三种装配方式可以混搭着来用 在这里通过一个例子来讲述配置 CD的两个实现,一个是ThinkingJAVA,一个是LinuxBird注解配置定义bean @Component public class ThinkingJAVA{ public void play(){ System.out.println("java思想"); } } 在这里ThinkingJAVA被C