spring框架学习(2)Bean

序言

Spring Bean到底是什么?解决什么问题?

解决主动new各种对象的问题

bean就是由IOC容器初始化、装配及管理的对象

Spring中的bean默认都是单例的,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。

@Bean和@Autowired 

通过反射实现@Autowired注解

spring有三种配置方式

  1. 基于XML
  2. 基于注解
  3. 基于java

一、XML配置

  1. instantiate bean对象实例化
  2. populate properties 封装属性
  3. 如果Bean实现BeanNameAware 执行 setBeanName
  4. 如果Bean实现BeanFactoryAware 或者 ApplicationContextAware 设置工厂 setBeanFactory 或者上下文对象 setApplicationContext
  5. 如果存在类实现 BeanPostProcessor(后处理Bean) ,执行postProcessBeforeInitialization
  6. 如果Bean实现InitializingBean 执行 afterPropertiesSet
  7. 调用<bean init-method="init"> 指定初始化方法 init
  8. 如果存在类实现 BeanPostProcessor(处理Bean) ,执行postProcessAfterInitialization
  9. 执行业务处理
  10. 如果Bean实现 DisposableBean 执行 destroy
  11. 调用<bean destroy-method="customerDestroy"> 指定销毁方法 customerDestroy

实战总结

1.对象交于Spring创建

  第一步:添加UserInfo

package cn.mf.bean;

public class UserInfo {

    private String name;
    private Integer age;
    private Car car;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public Car getCar() {
        return car;
    }
    public void setCar(Car car) {
        this.car = car;
    }
    @Override
    public String toString() {
        return "UserInfo [name=" + name + ", age=" + age + ", car=" + car
                + ", getName()=" + getName() + ", getAge()=" + getAge()
                + ", getCar()=" + getCar() + "]";
    }
}
View Code

 第二步:添加applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd ">
    <!-- 将User对象交给spring容器管理 -->
    <!-- Bean元素:使用该元素描述需要spring容器管理的对象
         class属性:被管理对象的完整类名.
         name属性:给被管理的对象起个名字.获得对象时根据该名称获得对象.  
                    可以重复.可以使用特殊字符.
         id属性: 与name属性一模一样. 
                    名称不可重复.不能使用特殊字符.
          结论: 尽量使用name属性.
      -->
    <bean  name="UserInfo" class="cn.mf.bean.UserInfo" ></bean>
</beans>

第三步:添加Junit测试

@Test
    public void fun1(){
        //1 创建容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("cn/mf/a_hello/applicationContext.xml");
        //2 向容器"要"UserInfo对象
        UserInfo u = ((UserInfo) ac.getBean("UserInfo"));
        //3 打印user对象
        System.out.println(u);
    }

2.配置详解-三种对象创建方式

1)空参构造方式

<bean  name="UserInfo" class="cn.mf.bean.User" ></bean>

2)静态工厂

<bean  name="user2"  class="cn.mf.b_create.UserFactory"   factory-method="createUser" ></bean>

 

public class UserFactory {

    public static User createUser(){
        System.out.println("静态工厂创建User");
        return new User();
    }
}

3)实例工厂

<bean  name="user3"  factory-bean="userFactory"  factory-method="createUser2" ></bean>     
<bean  name="userFactory"  class="cn.mf.b_create.UserFactory"   ></bean>

 

package cn.mf.b_create;
import cn.mf.bean.User;

public class UserFactory {
    public  User createUser2(){
        System.out.println("实例工厂创建User");
        return new User();
    }
}

3.Bean元素进阶——scope属性 

<bean  name="UserInfo" class="cn.mf.bean.UserInfo"  scope="singleton"></bean>

1)  singleton(默认值):scope="singleton" ,单例对象.被标识为单例的对象在spring容器中只会存在一个实例

2)  prototype:scope="prototype" ,多例原型.被标识为多例的对象,每次再获得才会创建.每次创建都是新的对象.整合struts2时,ActionBean必须配置为多例的.

3)  prototype:scope="request" ,request:web环境下.对象与request生命周期一致.(了解)

4)  prototype:scope="session" ,session:web环境下,对象与session生命周期一致.(了解)

4.Bean元素进阶——生命周期属性

1)init-method="init":配置一个方法作为生命周期初始化方法.spring会在对象创建之后立即调用.

2)destroy-method="destory":配置一个方法作为生命周期的销毁方法.spring容器在关闭并销毁所有容器中的对象之前调用.

<bean  name="user" class="cn.mf.bean.User" init-method="init" destroy-method="destory" ></bean>

测试

@Test
//测试生命周期方法
public void fun5(){
//1 创建容器对象
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("cn/mf/b_create/applicationContext.xml");
//2 向容器"要"user对象
User u = (User) ac.getBean("user");
//3 打印user对象
System.out.println(u);
//关闭容器,触发销毁方法
ac.close();
}

5.模块化配置

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd ">
    <!-- 主配置中导入其他spring配置文件 -->
    <import resource="cn/mf/b_create/applicationContext.xml"/>
</beans>

6.spring属性注入

1)set方法注入

<bean  name="user" class="cn.mf.bean.User" >
        <!--值类型注入: 为User对象中名为name的属性注入tom作为值 -->
        <property name="name" value="tom" ></property>
        <property name="age"  value="18" ></property>
        <!-- 引用类型注入: 为car属性注入下方配置的car对象 -->
        <property name="car"  ref="car" ></property>
 </bean>
<!-- 将car对象配置到容器中 -->
    <bean name="car" class="cn.mf.bean.Car" >
        <property name="name" value="兰博基尼" ></property>
        <property name="color" value="黄色" ></property>
</bean>

2)构造函数注入

<bean name="user2" class="cn.mf.bean.User" >
    <!-- name属性: 构造函数的参数名 -->
    <!-- index属性: 构造函数的参数索引 -->
    <!-- type属性: 构造函数的参数类型-->
    <constructor-arg name="name" index="0" type="java.lang.Integer" value="999"  ></constructor-arg>
    <constructor-arg name="car" ref="car" index="1" ></constructor-arg>
</bean>

3)p名称空间注入(了解)

<bean  name="user3" class="cn.mf.bean.User" p:name="jack" p:age="20" p:car-ref="car"> </bean>

4)spel注入(了解)

<bean  name="user4" class="cn.mf.bean.User" >
        <property name="name" value="#{user.name}" ></property>
        <property name="age" value="#{user3.age}" ></property>
        <property name="car" ref="car" ></property>
</bean>

5)复杂类型注入(了解)

<bean name="cb" class="cn.mf.c_injection.CollectionBean" >
    <!-- 如果数组中只准备注入一个值(对象),直接使用value|ref即可 
    <property name="arr" value="tom" ></property>
    -->
    <!-- array注入,多个元素注入 -->
    <property name="arr">
        <array>
            <value>tom</value>
            <value>jerry</value>
            <ref bean="user4" />
        </array>
    </property>
    
    <!-- 如果List中只准备注入一个值(对象),直接使用value|ref即可 
    <property name="list" value="jack" ></property>-->
    <property name="list"  >
        <list>
            <value>jack</value>
            <value>rose</value>
            <ref bean="user3" />
        </list>
    </property>
    <!-- map类型注入 -->
    <property name="map"  >
        <map>
            <entry key="url" value="jdbc:mysql:///crm" ></entry>
            <entry key="user" value-ref="user4"  ></entry>
            <entry key-ref="user3" value-ref="user2"  ></entry>
        </map> 
    </property>
    <!-- prperties 类型注入 -->
    <property name="prop"  >
        <props>
            <prop key="driverClass">com.jdbc.mysql.Driver</prop>
            <prop key="userName">root</prop>
            <prop key="password">1234</prop>
        </props>
    </property>
</bean>

二、使用注解代替xml配置

1.使用注解配置spring

1)开启使用注解代理配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd ">

<!-- 指定扫描cn.mf.bean报下的所有类中的注解. 注意:扫描包时.会扫描指定报下的所有子孙包-->
<context:component-scan base-package="cn.mf.bean"></context:component-scan>
</beans>

2.在类中使用注解完成配置

1)将对象注册到容器

//@Component("user")相当于//<bean name="user" class="cn.itcast.bean.User"  />
//@Service("user") // service层
//@Controller("user") // web层
@Repository("user")// dao层

2)修改对象的作用范围

//指定对象的作用范围
@Scope(scopeName="singleton")

3)值类型注入

通过反射的Field赋值,破坏了封装性

    @Value("18")
    private Integer age;

通过set方法赋值,推荐使用.

    @Value("tom")    
    public void setName(String name) {
        this.name = name;
    }

4)引用类型注入

@Autowired //自动装配
private Car car;

 

@Autowired //自动装配
@Qualifier("car2")//使用@Qualifier注解告诉spring容器自动装配哪个名称的对象
private Car car;

 

@Resource(name="car")//手动注入,指定注入哪个名称的对象
    private Car car;

5)初始化|销毁方法

@PostConstruct //在对象被创建后调用.init-method
    public void init(){
        System.out.println("我是初始化方法!");
    }
    @PreDestroy //在销毁之前调用.destory-method
    public void destory(){
        System.out.println("我是销毁方法!");
    }

实战总结

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd ">

<!-- 指定扫描cn.mf.bean报下的所有类中的注解. 注意:扫描包时.会扫描指定报下的所有子孙包-->
<context:component-scan base-package="cn.mf.bean"></context:component-scan>
<bean name="car2" class="cn.mf.bean.Car"  >
    <property name="name" value="布加迪威龙" ></property>
    <property name="color" value="black"  ></property>
</bean>
</beans>

User.java

package cn.mf.bean;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;


//<bean name="user" class="cn.itcast.bean.User"  />
//@Component("user")
//@Service("user") // service层
//@Controller("user") // web层
@Repository("user")// dao层
//指定对象的作用范围
@Scope(scopeName="singleton")
public class User {
    private String name;
    @Value("18")
    private Integer age;
    
    //@Autowired //自动装配
    //问题:如果匹配多个类型一致的对象.将无法选择具体注入哪一个对象.
    //@Qualifier("car2")//使用@Qualifier注解告诉spring容器自动装配哪个名称的对象
    
    @Resource(name="car")//手动注入,指定注入哪个名称的对象
    private Car car;
    
    public Car getCar() {
        return car;
    }
    public void setCar(Car car) {
        this.car = car;
    }
    public String getName() {
        return name;
    }
    @Value("tom")    
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    @PostConstruct //在对象被创建后调用.init-method
    public void init(){
        System.out.println("我是初始化方法!");
    }
    @PreDestroy //在销毁之前调用.destory-method
    public void destory(){
        System.out.println("我是销毁方法!");
    }
    @Override
    public String toString() {
        return "User [name=" + name + ", age=" + age + ", car=" + car + "]";
    }
    
}

Car.java

package cn.mf.bean;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component("car")
public class Car {
    @Value("玛莎拉蒂")
    private String  name;
    @Value("呕吐绿")
    private String color;
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    @Override
    public String toString() {
        return "Car [name=" + name + ", color=" + color + "]";
    }
    
    
}

Junit

@Test
    public void fun1(){        
        //1 创建容器对象
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2 向容器"要"user对象
        User u1 = (User) ac.getBean("user");
        User u2 = (User) ac.getBean("user");
        System.out.println(u1==u2);
        //3 打印user对象
        System.out.println(u1);
        ac.close();
    }

spring与junit整合测试

package cn.mf.b_test;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import cn.mf.bean.User;
//帮我们创建容器
@RunWith(SpringJUnit4ClassRunner.class)
//指定创建容器时使用哪个配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo {
    //将名为user的对象注入到u变量中
    @Resource(name="user")
    private User u;
    
    @Test
    public void fun1(){
        
        System.out.println(u);
        
    }
    
    @Test
    public void fun2(){
        
        System.out.println(u);
        
    }
    
    @Test
    public void fun3(){
        
        System.out.println(u);
        
    }
}
View Code

Bean的生命周期

 

ApplicationContext 

一、简单的用 ApplicationContext 做测试的话 , 获得 Spring 中定义的 Bean 实例(对象) 可以用:

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

如果是两个以上 , 可以使用字符串数组 :

ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml","SpringTest.xml"});

或者可以使用通配符:

ApplicationContext context = new ClassPathXmlApplicationContext("classpath:/*.xml");

小结

spring 中的id 和name 的区分

1. id 和name 属性作用上一样,推荐使用id;
posted @ 2017-04-16 18:51  ~沐风  阅读(362)  评论(0编辑  收藏  举报