JavaEE

JavaWeb了解之Spring框架(Ioc容器篇)

2022-10-14  本文已影响0人  平安喜乐698
目录

  前言
    1. Spring框架结构
    2. 第一个Spring项目(Hello World)
  1. Spring IoC容器
  2. 配置Bean (3种方式:XML、Java注解、Java代码)
  3. 依赖注入

Spring是一款开源的Java框架(用于简化JavaEE开发)。

Spring框架的优点
  1. 方便解耦,简化开发
    将所有对象的创建和依赖关系的维护交给SpringIoC容器来管理。
  2. 方便集成各种流行框架
    Struts2、Hibernate、MyBatis等。
  3. 降低JavaEE API的使用难度
    对JavaEE开发中一些难用的API(如:JDBC、JavaMail、远程调用等)进行了封装。
  4. 方便测试
    支持JUnit4,可以通过注解 方便地测试Spring程序。
  5. 支持AOP面向切面编程
    降低通用功能和业务逻辑的耦合。
  6. 支持声明式事务处理
    只需通过配置就可完成对事务的管理。

前言

  1. Spring框架结构
Spring框架
Spring框架说明:
  1. 核心容器(CoreContainer)
    由以下4个模块组成 :
      1. Beans模块
        提供BeanFactory(一个工厂模式的复杂实现),包含访问配置文件、创建和管理Bean、进行IoC容器及DI依赖注入操作的所有类。
      2. Core核心模块
        提供了Spring框架基本的核心工具类(其他模块都会使用到)。
      3. Context上下文模块
        基于Core和Beans模块,可用于获取配置的任何对象(ApplicationContext接口),还提供了许多企业级功能支持。
      4. SpEL表达式语言模块
        访问和修改 属性值、数组、容器、索引器,方法调用,命名变量,算数和逻辑运算,从Spring容器获取Bean,列表投影、选择和一般的列表聚合等。
  
  2. 数据访问/集成(DataAccess/Integration)
    由以下5个模块组成 :
      1. JDBC模块
        提供了JDBC抽象层(对JDBC、事务等操作进行了封装)。
      2. ORM模块
        方便集成 对象/关系映射(JPA、JDO、Hibernate、iBatis)。
      3. OXM模块
        方便集成 Object/XML映射(JAXB、Castor、XMLBeans、JiBX、XStream) 。
       4. JMS模块(Java消息服务) 
        提供了一套“消息生产者、消息消费者”模板来方便使用JMS。
        JMS用于在两个应用之间或分布式系统中发送消息,进行异步通信。
      5. Transactions模块
        支持编程和声明式事务管理。

  3. Web(MVC/Remoting)
    由以下4个模块组成 :
      1. Web模块
        提供了基本的Web开发功能(如:多文件上传功能、使用Servlet监听器和Web应用上下文的IoC容器)。
      2. Servlet模块
        提供了Spring MVC Web框架实现(基于注解的请求资源注入、更简单的数据绑定、数据验证、JSP标签等)。
      3. WebSocket模块
        提供了快速搭建WebSocket Server实现双向通讯的接口。
      4. Portlet模块
        提供了在Portlet环境中使用MVC实现类似Web-Servlet模块的功能。

  4.其他
    1. AOP模块
        提供了面向切面编程实现。提供 日志记录、权限控制、性能统计等通用功能和业务逻辑分离的技术(降低通用功能和业务逻辑的耦合)。
    2. Aspects模块
        提供与AspectJ(一个功能强大且成熟的面向切面编程AOP框架)的集成。
    3. Instrumentation模块
        提供了类工具的支持和类加载器的实现,可以在特定的应用服务器中使用。
    4. Messaging模块
        为STOMP提供了支持。
    5. Test测试模块
        支持JUnit、TestNG测试框架。

官网下载Spring框架commons-logging-xxx.jar

Spring框架目录
Spring框架目录说明
  1. docs
    Spring的API文档、开发规范
  2. libs
    开发需要的jar
  3. schema
    开发所需要的schema文件(定义了Spring相关配置文件的约束)

 libs目录下的jar说明
  1. spring-core.jar(必须)
    提供了基本的核心工具类(其它组件的核心)。
    依赖第三方jar包:commons-logging-xxx.jar。
  2. spring-beans.jar(必须)
    提供了基础IoC功能(提供了进行IoC/DI操作相关的所有类:访问配置文件、创建和管理bean、其他相关的类)。
  3. spring-context.jar(必须)
    在基础IoC功能上进行了扩展(邮件服务、任务调度、JNDI定位、EJB集成、远程访问、缓存、各种视图框架的封装)。提供了使用ApplicationContext时所需的全部类,JDNI所需的全部类,instrumentation组件以及校验Validation方面的相关类。
  4. spring-expression.jar(必须)
    提供了Spring表达式语言相关的所有类。
  5. spring-aop.jar
    提供了AOP特性相关的所有类。
  6. spring-jdbc.jar
    提供了SpringJDBC相关的所有类。
  7. spring-tx.jar
    提供了事务和异常处理相关的所有类(为JDBC、Hibernate、JDO、JPA等提供一致的声明式和编程式的事务管理)。
  7. spring-web.jar
    包含Web 应用开发时,用到Spring 框架时所需的核心类,包括自动载入Web Application Context 特性的类、Struts 与JSF 集成类、文件上传的支持类、Filter 类和大量工具辅助类。
    外部依赖spring-context, Servlet API, (JSP API, JSTL, Commons FileUpload, COS)。
  8. spring-webmvc.jar 
    包含Spring MVC 框架相关的所有类。包含国际化、标签、Theme、视图展现的FreeMarker、JasperReports、Tiles、Velocity、XSLT相关类。包括框架的Servlets,Web MVC框架,控制器和视图支持。
    如果应用使用了独立的MVC 框架,则无需这个JAR 文件里的任何类。
    外部依赖spring-web, (spring-support,Tiles,iText,POI)。
  9. spring-aspects.jar 
    提供对AspectJ的支持,以便可以方便的将面向方面的功能集成进IDE中,比如Eclipse AJDT。
  10. spring-context-support.jar
    Spring context的扩展支持,用于MVC方面。
  11. spring-instrument.jar
    Spring对服务器的代理接口
  12. spring-instrument-tomcat.jar
    Spring对tomcat连接池的集成
  13. spring-jms.jar
    为简化jms api的使用而做的简单封装。
    外部依赖spring-beans,spring-dao,JMS API。
  14. spring-orm.jar
    整合第三方的orm实现,如hibernate,ibatis,jdo以及spring 的jpa实现
  15. spring-oxm.jar
    Spring对于object/xml映射的支持,可以让JAVA与XML之间来回切换
  16. spring-messaging.jar:
  17. spring-test.jar
    对JUNIT等测试框架的简单封装
  19. spring-webmvc-portlet.jar
    Spring MVC的增强
  20. spring-websocket.jar:
  1. 第一个Spring项目(Hello World)
MyEclipse项目栏右击新建Java项目 | 点击项目右键 | Build Path | Config Build Path | Libraries | add External JARs |  1. 导入核心容器模块对应的4个jar(后期看需要再导入其他jar)或者 直接把spring的lib中所有的jar全部导入 ; 2. 导入commons-logging-xxx.jar
1. 新建HelloWorld.java文件(com.sst.cx包下)

  package com.sst.cx;
  public class HelloWorld {
       private String message;
       public void setMessage(String message){
          this.message  = message;
       }
       public void getMessage(){
          System.out.println("Your Message : " + message);
       }
       public void init(){
          System.out.println("Bean is going through init.");
       }
       public void destroy(){
          System.out.println("Bean will destroy now.");
       }
  }
2. 新建HelloBeans.xml(src下)
  定义各对象(分配唯一ID、属性赋值、依赖关系)。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
   <bean id="helloWorld" class="com.sst.cx.HelloWorld">
       <property name="message" value="Hello World!"/>
   </bean>
</beans>
3. 新建Main.java
  获取配置文件中的HelloWorld类实例,并调用其getMessage方法  

  package com.sst.cx;
  import org.springframework.context.ApplicationContext;
  import org.springframework.context.support.ClassPathXmlApplicationContext;
  public class Main {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("HelloBeans.xml");
            // HelloWorld obj = context.getBean("helloWorld", HelloWorld.class);
            HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
            obj.getMessage();
        }
  }

说明:
  1. ClassPathXmlApplicationContext类用于加载Spring配置文件,创建并初始化所有Bean对象。
  2. ApplicationContext.getBean()方法用于获取Bean,返回类型为Object。
4. 运行

Main.java文件 右键 | Run As Java Application运行程序,控制台会输出:
Your Message : Hello World!
添加Spring jar
运行

1. Spring IoC容器

Spring通过IoC容器来创建并管理所有Java对象(创建、初始化、依赖关系)。

1. IoC(Inversion of Control)控制反转
  是一种设计思想(最大限度地降低耦合度)。
  传统Java应用中,A类中想调用B类的属性或方法时,需要在代码中通过new创建B类的对象然后才能调用其属性或方法。A称为调用者,B称为被调用者,调用者掌握着被调用者的创建控制权。
  在Spring应用中,所有Java对象的创建控制权都由Ioc容器掌握。首先在配置文件(3种方式:XML、Java注释、Java代码)中对各个对象及依赖关系进行配置;Spring启动时,IoC容器会加载并解析这些配置文件,根据对象定义及依赖关系利用Java的反射机制创建并管理对象(被IoC容器创建并管理的对象被称为SpringBean);当需要使用某个Bean时直接从IoC容器中获取,而不是通过new方式创建。Ioc容器实现解耦的原理:对象的信息及依赖关系都是在配置文件中定义的,而不是在代码中紧密耦合,当对象发生改变后只需修改配置文件,而无需对Java代码进行修改。
  原本调用者为主动的一方,需要什么资源就自己去创建,在Spring中由IoC容器掌握主动权,原本的调用者需要被动的等待IoC容器创建自己所需的对象,即所谓的控制反转(控制权反转)。
  
2. DI(Denpendency Injection)依赖注入
  A类中有一个类型为B类的属性(A的对象依赖于B的对象),Spring的IoC容器在创建对象时会自动根据依赖关系,将依赖对象注入到当前对象中,即所谓的依赖注入。
IoC容器的2种实现:
  1. BeanFactory容器
    提供了IoC容器的基本功能(功能最简单的容器)。
    采用懒加载机制,Ioc容器在加载配置文件时并不会立即创建Java对象,只有在程序中使用到时才会创建。 
    移动设备或基于applet的应用的资源非常宝贵, 优先选择BeanFactory。
    在org.springframework.beans.factory.BeanFactory接口中定义。BeanFactory相关的接口(BeanFactoryAware,InitializingBean,DisposableBean)向后兼容其他三方框架。
  2. ApplicationContext容器
    在org.springframework.context.ApplicationContext接口(BeanFactory接口的子接口)中定义。
    对BeanFactory容器进行了扩展,增加了许多企业级功能(AOP、国际化、事务)。
    常用的实现类:
      1. FileSystemXmlApplicationContext
        需提供XML文件的完整路径("/"代表项目根目录)。
      2. ClassPathXmlApplicationContext
        不需要提供XML文件的完整路径。
        会在ClassPath下搜索XML文件(需正确配置ClassPath)。
      3. WebXmlApplicationContext
        在应用范围内搜索XML文件。
  1. BeanFactory容器
BeanFactory factory = new ClassPathXmlApplicationContext("HelloBeans.xml");  
HelloWorld obj = (HelloWorld) factory.getBean("helloWorld");   
obj.getMessage();
  1. ApplicationContext容器
// 创建和初始化所有对象(xml必须为完整路径, /代表项目根目录)
ApplicationContext context = new FileSystemXmlApplicationContext("/src/HelloBeans.xml");
HelloWorld obj = (HelloWorld) context.getBean("helloWorld");  
obj.getMessage();   
// 容器销毁 context.registerShutdownHook();

2. 配置Bean (3种方式:XML、Java注解、Java代码)

由Spring IoC容器创建和管理的Java对象称为Bean(Bean根据Spring配置文件中的信息创建)。

1. 当无法在类中添加注解时(如:DataSource、JdbcTemplate等第三方库中的类),使用xml方式配置。
2. 当前项目中的类使用注解方式配置更好。
3. 可一起联合使用。
  1. XML方式配置
根元素为beans,可包含多个子元素bean(每一个bean元素对应一个Bean对象)。
   <bean id="唯一标识" class="包路径.类名"></bean>

bean元素的常用属性
  1. id
    指定 Bean的唯一标识符(必须以字母开始,由字母、数字、下划线组成)
  2. name
    指定 Bean的名称(同一个Bean可指定多个名称,以,分隔)
  3. class  
    指定 Bean对应的类(完整路径)。
  4. scope  
    指定 【Bean的作用域】(5种)
      1. singleton  
        单例(默认)  ,(使用context.getBean方法)每次获取时都是同一个实例(仅对于该容器 即该容器共享同一个实例,一个Web应用会有多个容器)。
      2. prototype  
        每次获取时都创建新的实例。
      // ---------以下只在web的ApplicationContext的上下文中有效(XmlWebApplicationContext) ---------
      3. request    
        每次HTTP请求都会创建一个实例。
      4. session    
        同一个HTTP会话共享同一个实例。
      5. application
        同一个Web应用共享同一个实例。
      6. websocket
        在整个WebSocket中有效
    5. lazy-init
      延迟加载。设为true则使用时才会创建Bean实例;设为false则容器启动时就创建Bean实例。
      该方法只在scope=singleton时有效。
    6. init-method
      容器加载Bean时(所有必需的属性被容器设置之后)会调用该方法。
    7. destroy-method
      容器删除Bean时(容器被销毁时会删除容器中的Bean)会调用该方法。
      该方法只在scope=singleton时有效。
    对于初始化方法和销毁非法,分为全局指定和单个类指定:
      1. 全局指定:在beans元素中加 default-init-method="init" default-destroy-method="destroy"。
      2. 单个类指定:在bean元素中加 init-method="init" destroy-method="destroy"。
    8. parent 
      指定父Bean,与Java类的继承无关(子Bean和父Bean对应的实例不需要有继承关系)。子Bean可以继承父Bean的配置数据,也可以根据需要重写或添加属于自己的配置信息。
      例:
     <bean id="helloWorld" class="com.tutorialspoint.HelloWorld">
        <property name="message1" value="Hello"/>
        <property name="message2" value="World"/>
     </bean>
     <bean id="helloIndia" class="com.sst.cx.HelloIndia" parent="helloWorld">
        <property name="message1" value="Hi"/>
        <property name="message3" value="Hello World"/>
     </bean>
    9. abstract
      设置为true,可将父Bean定义为抽象模版(表明这个Bean是抽象的,不能被实例化,也不能被其他Bean引用,只能在子Bean的parent中引用)。
      例:
     <bean id="beanTeamplate" abstract="true">
      <property name="message1" value="Hello World!"/>
      <property name="message2" value="Hello Second World!"/>
      <property name="message3" value="Namaste India!"/>
     </bean>
    10. autowire(自动装配)
      把Bean与Bean之间建立依赖关系的行为称为装配。
      Spring容器可以在不使用<constructor-arg>和<property>的ref属性情况下,通过bean元素的autowire自动装配属性(根据装配规则为Bean从应用上下文中查找它所依赖的Bean并建立依赖关系)来简化XML内容。仍然可以使用ref属性进行“重写”。
      装配规则(5种)
        1. no
          不使用自动装配(默认)。
        2. byName
          按属性名自动装配。
          从所有IoC容器中寻找id/name和(使用自动装配bean对应实例的)属性名相同的bean,并建立依赖关系。
        3. byType
          按属性数据类型自动装配。
          从所有IoC容器中寻找class和(使用自动装配bean对应实例的)属性类型相同的bean,并建立依赖关系(如果存在多个对应的bean则异常)。
        4. constructor
          类似于byType,按构造函数的参数类型自动装配。
          从所有IoC容器中寻找class和(使用自动装配bean对应实例的)构造参数类型相同的bean,并建立依赖关系(如果不存在对应的构造函数参数类型的bean则异常)。
        5. default
          使用beans元素中的自动装配规则(beans元素的default-autowire属性)。
       自动装配的局限性:不能自动装配基础数据类型;没有显式装配精确。

bean元素的子元素(分别对应属性注入的2种方式)
  1. constructor-arg    
    通过Bean实例的带参构造函数实现Bean的属性注入(一个constructor-arg元素对应一个需要注入的属性)。
    name属性指定对应的构造参数名,value属性指定参数值。
    index属性指定构造参数的序号(从0开始)。type属性指定构造参数的类型。
  2. property   
    通过Bean实例的setter方法实现Bean的属性注入(一个property元素对应一个需要注入的属性)。
    name属性指定Bean实例相应的属性名,value属性指定属性值。

constructor-arg元素、property元素、其他元素的子元素
  1. ref
    用于引用某个Bean实例(Bean元素的id/name)    
  2. value
    用于指定一个常量值
  3. list
    注入 List或数组类型的属性
  4. set
    注入 Set类型的属性
  5. map
    注入 Map类型的属性
  6. entry(map元素的子元素)
    用于设置一个键值对
    key属性指定字符串类型的键,ref或value子元素指定其值。

示例

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
   <!-- 
      懒加载:lazy-init="true"
      初始化方法:init-method
      销毁方法:destroy-method
    -->
   <bean id="..." class="..." lazy-init="true" init-method="..." destroy-method="...">
   </bean>
</beans>
  1. 注解方式配置(简化xml文件内容)

通过注解可以在不改变原有代码逻辑的情况下,在源代码中嵌入补充信息。
从Spring2.5开始,可以对类、方法、属性添加注解来实现:配置Bean,实现依赖注入(会在xml配置的注入之前执行,所以会被覆盖)、自动装配。

1. 需要在xml配置文件中,开启注解功能。
  <!-- 会扫描包下的类,从类的注解中获取Bean的定义信息。例如:开启后如果类使用了@Component注解,则将该类配置到容器中。 -->
  <context:component-scan base-package="net.biancheng.c"></context:component-scan>
  <!-- 开启注解功能 -->
  <context:annotation-config/>
2. 配置Bean的注解(会被添加到IoC容器中)
  1. @Component注解
    将类标识为Bean。
  2. @Repository注解
    将Dao层(数据访问层)的类标识为Bean。
  3. @Service注解
    将Service层(业务层)的类标识为Bean。
  4. @Controller注解
    将Controller层(控制层)的类标识为Bean(如:Struts2的Action、SpringMVC的Controller)。
  例:@Component("helloBean")、@Repository("userDaoImpl")
  5. @Scope注解
    指定Bean的作用域
3. 实现依赖注入的注解
 1. @Autowired注解(自动装配,默认使用byType自动装配规则)
   可用在setter方法、非setter方法、构造函数、属性。
   1. 用在setter方法上(会自动使用byType,不用设置property)
     @Autowired
     public void setHelloB(HelloB helloB) {
         this.helloB = helloB;
     }
   2. 用在属性上(会自动使用byType,不用设置set方法)
     @Autowired
     HelloB helloB;
   3. 用在构造函数上(会自动使用byType,不用设置property)
     @Autowired
     public HelloWorld(HelloB helloB) {
         this.helloB = helloB;
     }
   4. 当没有匹配到时会报NoSuchBeanDefinitionException异常,可设置required属性为false来避免。
     @Autowired(required=false)  设为非必须(默认是必须的)
 2. @Qualifier注解(与@Autowired注解配合使用:@Autowired + @Qualifier)
   当匹配到多个相同类型的bean时使用,将自动装配规则由默认的byType修改为byName。
   例:
     @Autowired
     @Qualifier("helloB1")
     private HelloB helloB;
 3. @Resource注解(自动装配,默认使用byName自动装配规则)
   如果指定name属性,则按byName进行装配;
   如果指定type属性,则按byType进行装配;
   如果都不指定,则先按byName进行装配,如果没有找到则再按byType进行装配;如果都无法匹配,则抛出NoSuchBeanDefinitionException异常。
 4. @Value注解(注入普通属性值)
   @Value("张三")
 5. @Nullable注解(注入null)
4. 生命周期相关的注解
  1. @PostConstruct注解 
    标识为初始化方法(指定为init-method)
  2. @PreDestroy注解
    标识为销毁方法(指定为destroy-method)
5. 其他
  1. @Required注解
    用于setter方法上。表示相应的bean属性必须进行注入,否则BeanInitializationException异常。
    例:
      @Required
      public void setName(String name) {
          this.name = name;
      }
      <bean id="helloWorld" class="com.sst.cx.HelloWorld">
          <property name="name" value="cx"/>
      </bean>
  2. @Test注解
  1. Java代码方式配置

可以完全摆脱xml配置文件。

配置类相关的注解
  1. @Configuration注解
    标识该类为配置类(一个配置类等价于一个xml配置文件)。
    获取容器:ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    当有多个配置类时:
     public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.register(AppConfig.class, OtherConfig.class);
        ctx.register(AdditionalConfig.class);
        ctx.refresh();
        MyService myService = ctx.getBean(MyService.class);
        myService.doStuff();
     }
  2. @Bean注解
    将该类注册到IoC容器中(所修饰的方法相当于Bean的id属性,方法返回类型相当于Bean的class属性)。
    获取容器中的对象:Foo foo = ctx.getBean(Foo.class);
  3. @Import注解
    导入其他配置类(从其他配置类中加载@Bean定义)。

  例:
    @Import(ConfigA.class)
    @Configuration
    public class AppConfig {
        @Bean
        public Foo foo() {
            return new Foo(bar());  // 依赖注入
        }
        @Bean
        public Bar bar() {
            return new Bar();
        }
        @Bean(initMethod = "init", destroyMethod = "cleanup" )
        public HelloB helloB(){ // HelloB类中有init、cleanup方法
          return new HelloB();
        }
        @Bean
        @Scope("prototype")
        public HelloB helloB(){ 
          return new HelloB();
        }
    }

Bean生命周期

主要分为
  1. 实例化阶段
    向容器请求一个尚未初始化的bean时 或 初始化bean时需要注入另一个尚末初始化的依赖时,容器就会调用doCreateBean()方法创建Bean并进行实例化(给属性赋值属性)。
  2. 初始化阶段
    1. 执行Aware接口的方法(如果Bean实现了xxxAware接口)。通过Aware类型的接口可以获取到Spring容器的一些资源。如:实现BeanNameAware接口可以获取到BeanName,实现BeanFactoryAware接口可以获取到工厂对象BeanFactory等。
    2. 执行BeanPostProcessor的前置处理方法postProcessBeforelnitialization()方法(如果Bean实现了BeanPostProcessor接口),此时Bean已经创建但未初始化。
    3. 执行afeterPropertiesSet()初始化方法(如果Bean实现了InitializingBean接口)
    4. 执行自定义的初始化方法(如果在bean元素的init-method属性中进行了配置)。
    5. 执行BeanPostProcessor的后置处理方法postProcessAfterinitialization()方法(如果Bean实现了BeanPostProcessor接口)此时Bean已经初始化。
  3. 销毁阶段
    1. 执行DestructionAwareBeanPostProcessor后置处理方法postProcessBeforeDestruction()方法(如果Bean实现了DestructionAwareBeanPostProcessor接口)。
    2. 执行DisposableBean的destroy()方法(如果Bean实现了DisposableBean接口)。
    3. 执行自定义的销毁方法(如果在bean元素的destroy-method属性中进行了配置)。
Bean的生命周期

后置处理器

Spring提供了如下后置处理器
  1. BeanFactoryPostProcessor
  2. BeanPostProcessor
  3. InitializingBean

如果bean实现了以上接口中的方法,这些方法会在bean初始化时调用,可以做一些前置、后置处理。
例(BeanPostProcessor)

===》InitHelloWorld.java
package com.sst.cx;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class InitHelloWorld implements BeanPostProcessor {
     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
          System.out.println("BeforeInitialization : " + beanName);
          return bean;  
       }
       public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
          System.out.println("AfterInitialization : " + beanName);
          return bean;  
       }
}

3. 依赖注入(即给属性赋值)

2种:
  1. 基于构造函数的属性注入
  2. 基于setter的属性注入
  1. 基于构造函数的属性注入

通过Bean实例的带参构造函数实现Bean的属性注入。

1. 根据构造函数的参数名
    <bean id="student" class="net.biancheng.c.Student">
        <constructor-arg name="id" value="2"></constructor-arg>
   </bean>

2. 根据构造函数的参数顺序
   <bean id="exampleBean" class="examples.ExampleBean">
      <constructor-arg type="int" value="2001"/>
      <constructor-arg type="java.lang.String" value="Zara"/>
   </bean>
  或
   <bean id="exampleBean" class="examples.ExampleBean">
      <constructor-arg index="0" value="2001"/>
      <constructor-arg index="1" value="Zara"/>
   </bean>

示例

1. Grade年级类
package net.biancheng.c;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Grade {
    private static final Log LOGGER = LogFactory.getLog(Grade.class);
    private Integer gradeId;
    private String gradeName;
    public Grade(Integer gradeId, String gradeName) {
        LOGGER.info("正在执行 Course 的有参构造方法,参数分别为:gradeId=" + gradeId + ",gradeName=" + gradeName);
        this.gradeId = gradeId;
        this.gradeName = gradeName;
    }
    @Override
    public String toString() {
        return "Grade{" +
                "gradeId=" + gradeId +
                ", gradeName='" + gradeName + '\'' +
                '}';
    }
}

2. Student学生类
package net.biancheng.c;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Student {
    private static final Log LOGGER = LogFactory.getLog(Student.class);
    private int id;
    private String name;
    private Grade grade;
    public Student(int id, String name, Grade grade) {
        LOGGER.info("正在执行 Course 的有参构造方法,参数分别为:id=" + id + ",name=" + name + ",grade=" + grade);
        this.id = id;
        this.name = name;
        this.grade = grade;
    }
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", grade=" + grade +
                '}';
    }
}

3. xml文件配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    <bean id="student" class="net.biancheng.c.Student">
        <constructor-arg name="id" value="2"></constructor-arg>
        <constructor-arg name="name" value="李四"></constructor-arg>
        <constructor-arg name="grade" ref="grade"></constructor-arg>
    </bean>
    <bean id="grade" class="net.biancheng.c.Grade">
        <constructor-arg name="gradeId" value="4"></constructor-arg>
        <constructor-arg name="gradeName" value="四年级"></constructor-arg>
    </bean>
</beans>

4. 测试
package net.biancheng.c;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
    private static final Log LOGGER = LogFactory.getLog(MainApp.class);
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        Student student = context.getBean("student");
        LOGGER.info(student.toString());
    }
}
  1. 基于setter的属性注入

通过Bean实例的setter方法实现Bean的属性注入。

根据属性名
    <bean id="student" class="net.biancheng.c.Student">
        <property name="id" value="1"></property>
        <property name="grade" ref="grade"></property>
    </bean>

在Spring实例化Bean的过程中,IoC容器首先会调用默认的构造方法(无参构造方法)实例化Bean(Java对象),然后通过Java的反射机制根据属性名调用Bean的setter方法 将属性值注入到Bean中。
有其他带参构造函数时需创建一个无参构造函数(没有其他带参构造函数时无需创建)。

示例

1. Grade年级类
package net.biancheng.c;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Grade {
    private static final Log LOGGER = LogFactory.getLog(Grade.class);
    private Integer gradeId;
    private String gradeName;
    // 无参构造方法。在没有其他带参构造方法时可以省略。
    public Grade() {
    }
    public void setGradeId(Integer gradeId) {
        LOGGER.info("正在执行 Grade 类的 setGradeId() 方法…… ");
        this.gradeId = gradeId;
    }
    public void setGradeName(String gradeName) {
        LOGGER.info("正在执行 Grade 类的 setGradeName() 方法…… ");
        this.gradeName = gradeName;
    }
    @Override
    public String toString() {
        return "Grade{" +
                "gradeId=" + gradeId +
                ", gradeName='" + gradeName + '\'' +
                '}';
    }
}

2. Student学生类
package net.biancheng.c;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Student {
    private static final Log LOGGER = LogFactory.getLog(Student.class);
    private int id;
    private String name;
    private Grade grade;
    // 无参构造方法。在没有其他带参构造方法时可以省略。
    public Student() {
    }
    public void setId(int id) {
        LOGGER.info("正在执行 Student 类的 setId() 方法…… ");
        this.id = id;
    }
    public void setName(String name) {
        LOGGER.info("正在执行 Student 类的 setName() 方法…… ");
        this.name = name;
    }
    public void setGrade(Grade grade) {
        LOGGER.info("正在执行 Student 类的 setGrade() 方法…… ");
        this.grade = grade;
    }
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", grade=" + grade +
                '}';
    }
}

3. xml文件配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    <bean id="student" class="net.biancheng.c.Student">
        <property name="id" value="1"></property>
        <property name="name" value="张三"></property>
        <property name="grade" ref="grade"></property>
    </bean>
    <bean id="grade" class="net.biancheng.c.Grade">
        <property name="gradeId" value="3"></property>
        <property name="gradeName" value="三年级"></property>
    </bean>
</beans>
  1. 短命名空间注入(对上述2种方式进行简化)
1. c命名空间(构造函数方式注入的快捷实现)  
  需要在beans元素中引入XML约束xmlns:c="http://www.springframework.org/schema/c"
  以bean属性的形式(c:普通属性="属性值" c:对象属性="对象的引用")代替<constructor-arg> 元素。
  
2. p命名空间(setter方式注入的快捷实现)
  需要在beans元素中引入XML约束xmlns:p="http://www.springframework.org/schema/p"
  以bean属性的形式(p:普通属性="属性值" p:对象属性="对象的引用")代替<property> 元素。
  1. 注入内部Bean(属性类型为类类型)

将定义在property元素、constructor-args元素内部的bean称为内部bean。

例(HelloWorld类有一个HelloB类型属性helloB,HelloB类有个name属性)

  方式1. setter方式注入(需要一个无参构造函数、一个set方法)
   <bean id="helloWorld" class="com.sst.cx.HelloWorld">
      <property name="helloB">
         <bean class="com.sst.cx.HelloB">
           <property name="name" value="张三"/>
         </bean>
       </property>
   </bean>

  方式2. 构造函数方式注入(构造函数需要一个HelloB类型的参数helloB)
   <bean id="helloWorld" class="com.sst.cx.HelloWorld">
      <constructor-args name="helloB">
         <bean class="com.sst.cx.HelloB">
           <constructor-args name="name" value="张三"/>
         </bean>
      </constructor-args>
   </bean>
  1. 注入集合(属性类型为集合)
在property元素中添加如下子元素来配置集合值:
  1. list元素
    注入一列值(允许重复)
  2. set元素  
    注入一列值(不能重复)
  3. map元素
    注入键值对(键值可以是任何类型)
  4. props元素
    注入键值对(键值都为字符串类型)
  5. array元素
    注入

  注入引用(集合中的元素为类类型时)
      <property name="addressSet或addressList">
         <list>
           <value>A</value>
            <ref bean="helloBean"/>
         </list>
      </property>
      <property name="addressMap">
         <map>
            <entry key="one" value="A"/>
            <entry key ="two" value-ref="helloBean"/>
         </map>
      </property>
      <property name="addressArray">
         <array>
            <ref bean="helloBean"/>
         </array>
      </property>

示例

1. HelloWorld.java
  package com.sst.cx;
  import java.util.*;
  public class HelloWorld {
    private List<String> addressList;
    private Set<String>  addressSet;
    private Map<String,String>  addressMap;
    private Properties addressProp;
    private String[] addressArray;
        //
    public List getAddressList() {
        System.out.println("List Elements :"  + addressList);
        return addressList;
    }
    public void setAddressList(List<String> addressList) {
        this.addressList = addressList;
    }
    public Set getAddressSet() {
        System.out.println("Set Elements :"  + addressSet);
        return addressSet;
    }
    public void setAddressSet(Set<String> addressSet) {
        this.addressSet = addressSet;
    }
    public Map getAddressMap() {
        System.out.println("Map Elements :"  + addressMap);
        return addressMap;
    }
    public void setAddressMap(Map<String,String> addressMap) {
        this.addressMap = addressMap;
    }
    public Properties getAddressProp() {
        System.out.println("Property Elements :"  + addressProp);
        return addressProp;
    }
    public void setAddressProp(Properties addressProp) {
        this.addressProp = addressProp;
    }
    public String[] getAddressArray() {
        System.out.println("Array Elements :"  + addressArray);
        return addressArray;
    }
    public void setAddressArray(String[] addressArray) {
        this.addressArray = addressArray;
    }
  }

2. Beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
   <bean id="helloWorld" class="com.sst.cx.HelloWorld">
      <property name="addressList">
         <list>
            <value>A</value>
            <value>B</value>
            <value>C</value>
            <value>C</value>
         </list>
      </property>
      <property name="addressSet">
         <set>
            <value>A</value>
            <value>B</value>
            <value>C</value>
            <value>C</value>
        </set>
      </property>
      <property name="addressMap">
         <map>
            <entry key="1" value="A"/>
            <entry key="2" value="B"/>
            <entry key="3" value="C"/>
            <entry key="4" value="C"/>
         </map>
      </property>
      <property name="addressProp">
         <props>
            <prop key="one">A</prop>
            <prop key="two">B</prop>
            <prop key="three">C</prop>
            <prop key="four">C</prop>
         </props>
      </property>
      <property name="addressArray">
         <array>
            <value>A</value>
            <value>B</value>
            <value>C</value>
            <value>C</value>
         </array>
      </property>
   </bean>
</beans>

3. Main.java
  package com.sst.cx;
  import org.springframework.context.ApplicationContext;
  import org.springframework.context.support.ClassPathXmlApplicationContext;
  public class Main {
       public static void main(String[] args) {
               ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
               HelloWorld helloW = (HelloWorld)context.getBean("helloWorld");
               helloW.getAddressList();
               helloW.getAddressSet();
               helloW.getAddressMap();
               helloW.getAddressProp();
       }
  }
  1. 注入其他类型

除了基础数据类型属性、类类型属性、集合外,也支持注入其他类型:Null值、特殊符号。

null值
  <property name="nullValue">
    <null/>
  </property>

特殊符号
  在XML配置文件中"<、>、"、'、&"等特殊字符是不能直接保存的,否则XML语法检查时就会报错。
  解决:
  方式1. 转义后保存。
    转义序列字符之间不能有空格;
    转义序列必须以“;”结束;
    单独出现的“&”不会被认为是转义的开始;
    区分大小写
  方式2. 将特殊符号包含在<![CDATA[特殊符号写在这里]]>中。
    不允许嵌套;]]>不能有空格或换行;
    <property name="num">
      <![CDATA[<<12345678>>]]>
    </property>
上一篇下一篇

猜你喜欢

热点阅读