Spring Bean作用域
- singleton 单例模式
Spring IOC容器中只会有一个共享的Bean实例,无论有多少个Bean引用它,始终指向同一个对象。该模式在多线程下是不安全的。在Spring中是缺省作用域,也可以显示定义:
<bean id = "userDao" class = "com.xzp.userDaoImpl" scope = "singleton"/>
- prototype 原型模式
每次通过容器获取Bean实例时,容器都将创建一个新的Bean,每个Bean实例都有自己的属性和状态,而singleton全局只有一个对象。 - request
再一次HTTP请求中,容器会返回该Bean的同一实例。不同的HTTP请求,产生不同的Bean,请求结束,Bean实例销毁。
<bean id = "userDao" class = "com.xzp.userDaoImpl" scope = "request"/>
- session
在一个HTTP Session会话中,容器会返回该Bean的同一实例。仅在当前Session中有效,Session请求结束,Bean实例会被销毁。
<bean id = "userDao" class = "com.xzp.userDaoImpl" scope = "session"/>
- global session
在一个全局的Http Session中,容器会返回该Bean的同一个实例,仅在使用portlet context时有效。
Spring Bean生命周期
-
实例化
实例化一个 Bean,也就是我们常说的 new。
-
IOC依赖注入
按照 Spring 上下文对实例化的 Bean 进行配置,也就是 IOC 注入。
-
setBeanName实现
如果这个 Bean 已经实现了 BeanNameAware 接口,会调用它实现的 setBeanName(String)方法, 此处传递的就是 Spring 配置文件中 Bean 的 id 值
-
BeanFactoryAware实现
如果这个 Bean 已经实现了 BeanFactoryAware 接口,会调用它实现的 setBeanFactory, setBeanFactory(BeanFactory)传递的是 Spring 工厂自身(可以用这个方式来获取其它 Bean, 只需在 Spring 配置文件中配置一个普通的 Bean 就可以)。
-
ApplicationContextAware实现
如果这个 Bean 已经实现了 ApplicationContextAware 接口,会调用setApplicationContext(ApplicationContext)方法, 传入 Spring 上下文(同样这个方式也可以实现步骤 4 的内容,但比 4 更好,因为 ApplicationContext 是 BeanFactory 的子接口,有更多的实现方法)。
-
postProcessBeforeInitialization 接口实现-初始化预处理
如果这个 Bean 关联了 BeanPostsdfProcessor 接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法, BeanPostProcessor 经常被用作是 Bean 内容的更改,并且由于这个是在 Bean 初始化结束时调用那个的方法, 也可以被应用于内存或缓存技术。
-
init-method
如果 Bean 在 Spring 配置文件中配置了 init-method 属性会自动调用其配置的初始化方法。
-
postProcessAfterInitialization
如果这个 Bean 关联了 BeanPostProcessor 接口,将会调用postProcessAfterInitialization(Object obj, String s)方法。 注:以上工作完成以后就可以应用这个 Bean 了,那这个 Bean 是一个 Singleton 的, 所以一般情况下我们调用同一个 id 的 Bean 会是在内容地址相同的实例,当然在 Spring 配置文件中也可以配置非Singleton。
-
Destroy 过期自动清理阶段
当 Bean 不再需要时,会经过清理阶段,如果 Bean 实现了 DisposableBean 这个接口,会调用那个其实现的 destroy()方法;
10.destroy-method 自配置清理
最后,如果这个 Bean 的 Spring 配置中配置了 destroy-method 属性,会自动调用其配置的销毁方法。
如下图:
**注:
bean 标签有两个重要的属性(init-method 和 destroy-method)。用它们你可以自己定制
初始化和注销方法。它们也有相应的注解(@PostConstruct 和@PreDestroy)。
<bean id="" class="" init-method="初始化方法" destroy-method="销毁方法">
Spring 依赖注入的几种方式
- set注入
创建Student对象
package cn.happy.entity;
public class Student {
private String sname;
private Integer sage;
public Integer getSage() {
return sage;
}
public void setSage(Integer sage) {
this.sage = sage;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
}
配置applicationContext.xml:
<!--set 注入 prototype 原型 singletion 单例-->
<bean id="stu" class="cn.happy.entity.Student" scope="prototype">
<property name="sname" value="张三"></property>
<property name="sage" value="11"></property>
</bean>
测试类中:
//被Spring管理的bean默认都是单例的
@Test
public void myTest1(){
//ac 就是Spring容器
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
Student stu=(Student) ac.getBean("stu");
Student stu1=(Student) ac.getBean("stu");
System.out.println(stu+"\n"+stu1);
}
- 构造器注入
对象中添加构造:
public class UserService implements IUserService {
private IUserDao userDao;
public UserService(IUserDao userDao) {
this.userDao = userDao;
}
public void loginUser() {
userDao.loginUser();
}
}
配置文件:
<!-- 注册userService -->
<bean id="userService" class="com.lyu.spring.service.impl.UserService">
<constructor-arg ref="userDaoJdbc"></constructor-arg>
</bean>
<!-- 注册jdbc实现的dao -->
<bean id="userDaoJdbc" class="com.lyu.spring.dao.impl.UserDaoJdbc"></bean>
@Test
public void testDI() {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取bean对象
UserService userService = ac.getBean(UserService.class, "userService");
// 模拟用户登录
userService.loginUser();
}
- 空间命名注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
//注入p
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!--命名空间P注入-->
<bean id="car2" class="cn.happy.entity.Car">
<property name="cname" value="毛驴"></property>
</bean>
<bean id="stu2" class="cn.happy.entity.Student" p:sname="李四" p:sage="18" p:car-ref="car2"></bean>
//构造注入 命名空间注入
@Test
public void myTest2(){
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
Student stu1=(Student) ac.getBean("stu1");
Student stu2=(Student) ac.getBean("stu2");
System.out.println("构造:"+stu1+"\n命名空间:"+stu2);
}
- 集合注入
<!--list集合属性注入-->
<bean id="collection1" class="cn.happy.entity.MyCollection">
<property name="list">
<list>
<value>哈哈</value>
<value>呵呵</value>
<value>嘿嘿</value>
</list>
</property>
</bean>
<!--set集合属性注入-->
<bean id="collection2" class="cn.happy.entity.MyCollection">
<property name="set">
<set>
<value>哈哈</value>
<value>呵呵</value>
<value>嘿嘿</value>
</set>
</property>
</bean>
<!--Map集合属性注入-->
<bean id="collection3" class="cn.happy.entity.MyCollection">
<property name="map">
<map>
<entry key="001">
<value>呵呵</value>
</entry>
<entry key="002">
<value>哈哈</value>
</entry>
<entry key="003">
<value>嘿嘿</value>
</entry>
</map>
</property>
</bean>
- 注解注入(最多)
package cn.happy.entity;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
/**
* Created by CKW on 2017/3/22.
*/
@Component("car") //不分层
/*@Repository //dao层*/
/*@Service //biz层*/
/*@Controller //action层*/
public class Car {
@Value("特斯拉")
private String cname;
@Override
public String toString() {
return getCname();
}
public Car() {
}
public Car(String cname) {
this.cname = cname;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
}
package cn.happy.entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* Created by CKW on 2017/3/22.
*/
@Component("student")
public class Student {
@Value("撒打发")
private String sname;
@Value("20")
private Integer sage;
//jdk注解
// @Resource
@Autowired
@Qualifier("car")
private Car car;
@Override
public String toString() {
return "name="+getSname()+",age="+getSage()+",car="+getCar();
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
public Student() {
}
public String getSname() {
return sname;
}
public Student(String sname, Integer sage, Car car) {
this.sname = sname;
this.sage = sage;
this.car = car;
}
public void setSname(String sname) {
this.sname = sname;
}
public Integer getSage() {
return sage;
}
public void setSage(Integer sage) {
this.sage = sage;
}
}
配置applicationContext.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
***xmlns:context="http://www.springframework.org/schema/context"***
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
***http://www.springframework.org/schema/context***
***http://www.springframework.org/schema/context/spring-context.xsd***
">
<!--注解-->
<!--配置包扫描器-->
<context:component-scan base-package="cn.happy.entity"></context:component-scan>
//注解
@Test
public void myTest4(){
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
Student stu=(Student)ac.getBean("student");
System.out.println(stu.getCar().getCname());
}