一、Bean的配置二、Bean的实例化
2.1 构造方法实例化2.2 静态工厂实例化2.3 实例工厂实例化 三、Bean的作用域
3.1 singleton 作用域3.2 prototype 作用域 四、Bean的生命周期五、Bean的装配方式
5.1 基于XML配置的装配5.2 基于注解的装配
spring学习记录
在Spring应用中,Spring IOC容器可以创建、装配和配置应用组件对象,这里的组件对象称为Bean。 一、Bean的配置
Spring可以看作一个大型工厂,用于生产和管理Spring容器中的Bean。如果要使用这个工厂生产和管理Bean,需要开发者将Bean配置在Spring的配置文件(支持XML和Properties)中。
XML配置文件的根元素是
| 属性或子元素名称 | 描述 |
|---|---|
| id | Bean在BeanFactory中的唯一标识,在代码中通过BeanFactory获取Bean实例时需要作为索引名称 |
| class | Bean的具体实现类,使用类的名 |
| scop | 指定Bean实例的作用域 |
Bean的配置示例代码:
二、Bean的实例化
在Spring框架中,如果想使用Spring容器中的Bean,需要实例化Bean。Spring框架示例化Bean有3中方式,构造方法实例化(常用)、静态工厂实例化和示例实例实例化。
2.1 构造方法实例化在Spring框架中,Spring容器可以调用Bean对应类中的无参构造方法来实例化Bean,这种方式称为构造方法实例化。
- 准备一个spring项目或者web项目导入spring jar包
需要的基本jar包:
commons-logging-1.2.jarspring-beans-5.2.3.RELEASE.jarspring-context-5.2.3.RELEASE.jarspring-core-5.2.3.RELEASE.jarspring-expression-5.2.3.RELEASE.jar
- src目录下新建一个instance包,并创建BeanClass类
定义一个message字符串测试无参构造方法实例化Bean。
public class BeanClass {
public String message;
public BeanClass(){
message = "构造方法实例化Bean";
}
public BeanClass(String s){
message = s;
}
- src目录下的创建applicationContext.xml配置文件
定义一个id为constructorInstance的Bean
- 测试类测试构造方法实例化
public class SpringTest {
public static void main(String[] args) {
//初始化Spring容器的ApplicationContext,加载配置文件
ApplicationContext applicationContext =new ClassPathXmlApplicationContext("applicationContext.xml");
//测试构造方法实例化Bean
BeanClass beanClass = (BeanClass) applicationContext.getBean("constructorInstance");
System.out.println(beanClass + beanClass.message);
}
}
- 测试结果
使用静态工厂实例化时要求在工厂类中创建一个静态方法来创建Bean的实例。
- 在instance包中创建工厂类BeanStaticFactory
使用静态方法createInstance()实例化对象。
public class BeanStaticFactory {
private static BeanClass beanInstance = new BeanClass("调用静态工厂方法实例化Bean");
public static BeanClass createInstance(){
return beanInstance;
}
}
- 在applicationContext.xml文件中配置Bean
class属性指定静态工厂类,factory-method属性指定工厂类中的静态方法
- 测试类中进行测试
public class SpringTest {
public static void main(String[] args) {
//初始化Spring容器的ApplicationContext,加载配置文件
ApplicationContext applicationContext =new ClassPathXmlApplicationContext("applicationContext.xml");
//测试构造方法实例化Bean
BeanClass beanClass = (BeanClass) applicationContext.getBean("constructorInstance");
System.out.println(beanClass + beanClass.message);
//测试静态工厂实例化Bean
BeanClass beanClass2 = (BeanClass) applicationContext.getBean("staticFactoryInstance");
System.out.println(beanClass2 + beanClass2.message);
}
}
- 测试结果
实例工厂实例化Bean时要求开发者在工厂类中建立一个实例方法来出啊那赶紧Bean的实例
- 创建工厂类BeanInstanceFactory
创建实例方法createBeanClassInstance实例化BeanClass对象
public class BeanInstanceFactory {
public BeanClass createBeanClassInstance() {
return new BeanClass("调用实例工厂方法实例化Bean");
}
}
- 在applicationContext.xml文件中配置Bean
配置Bean时需要使用factory-bean属性指定配置工厂,使用factory-method属性指定使用工厂中的那个方法实例化Bean
- 测试类进行测试
public class SpringTest {
public static void main(String[] args) {
//初始化Spring容器的ApplicationContext,加载配置文件
ApplicationContext applicationContext =new ClassPathXmlApplicationContext("applicationContext.xml");
//测试构造方法实例化Bean
BeanClass beanClass = (BeanClass) applicationContext.getBean("constructorInstance");
System.out.println(beanClass + beanClass.message);
//测试静态工厂实例化Bean
BeanClass beanClass2 = (BeanClass) applicationContext.getBean("staticFactoryInstance");
System.out.println(beanClass2 + beanClass2.message);
//测试实例化工厂实例化Bean
BeanClass beanClass3 = (BeanClass) applicationContext.getBean("instanceFactoryInstance");
System.out.println(beanClass3 + beanClass3.message);
}
}
- 测试结果
以上为Bean实例化的三种方法。
三、Bean的作用域| 作用域名称 | 描述 |
|---|---|
| singleton | 默认的作用域,使用singleton定义的Bean在Spring容器中只有一个Bean实例 |
| prototype | Spring容器每次获取prototype定义的Bean,容器都将创建一个新的Bean实例 |
| request | 在一次HTTP请求中容器将返回一个Bean实例,不同的HTTP请求返回不同的Bean实例。仅在Web Spring 应用程序上下文中使用 |
| session | 在一个HTTP Session中,容器将返回同一个Bean实例。仅在Web Spring 应用程序上下文中使用 |
| application | 为每个ServeltContext对象创建一个实例,即同一个应用共享一个Bean实例。仅在Web Spring 应用程序上下文中使用 |
| websocket | 为每个WebSockert对象创建一个Bean实例。仅在Web Spring 应用程序上下文中使用 |
其中singeton 和 prototype是最常用两种,其他作用域仅在仅在Web Spring 应用程序上下文中使用。
3.1 singleton 作用域当bean的scope设置为singleton时,SpringIoC容器仅生成盒管理一个Bean实例。在使用id或者name获取Bean实例时,IoC容器将返回共享的Bean实例
- 例如之前的构造方法实例化Bean配置文件,
或者是
- 测试类测试
public class SpringTest {
public static void main(String[] args) {
//初始化Spring容器的ApplicationContext,加载配置文件
ApplicationContext applicationContext =new ClassPathXmlApplicationContext("applicationContext.xml");
//测试构造方法实例化Bean
BeanClass beanClass1 = (BeanClass) applicationContext.getBean("constructorInstance");
System.out.println(beanClass1);
BeanClass beanClass2 = (BeanClass) applicationContext.getBean("constructorInstance");
System.out.println(beanClass2);
- 结果
可以看出返回的Bean实例只有一个。
3.2 prototype 作用域- 同理,配置文件将scope设置为"prototype"
- 测试类测试测试结果
可以看出,两次获取Bean实例时,IoC容器返回两个不同的Bean实例。
一个对象的生命周期包括创建(实例化与初始化)、使用以及销毁等阶段,Spring中,Bean对象周期也遵循这一过程,但是Spring提供了许多对外接口,允许开发者对三个过程(实例化、初始化、销毁)的前后做一些操作。在Spring Bean中,实例化时为Bean对象开辟空间,初始化则是对属性的初始化。
Spring容器可以管理singleton作用域Bean的生命周期,在此作用域下,Spring能够精确知道Bean何时被创建,何时初始化完成,以及何时被销毁。对于prototype作用域的Bean,Spring只负责创建,当容器创建了Bean实例后,Bean实例就交给了客户端的代码管理器,Spring容器将不再跟踪其生命周期,并且不会管理那些被配置成prototype作用域的Bean。
Bean生命周期:
- 根据Bean的配置情况实例化一个Bean根据Sprig上下文对实例化的Bean进行依赖注入,即对Bean的属性进行初始化如果Bean实现了BeanNameAware接口,将调用它实现的setBeanName(String BeanId)方法,此处参数传的是Sping配置文件Bean的id。如果Bean实现了BeanFactoryAware接口,将调用它实现的SetBeanFactory方法,此处参数传递的是当前Spring工厂实例的引用。如果Bean实现了ApplicationContextAware接口,将调用它实现的SetApplicationContext(ApplicationContext)方法,此处参数传递的是Spring上下文实例的引用。如果Bean关联了BeanPostProcessor接口,将调用初始化方法postProcessBeforeInitialization(Object obj,String s)对Bean操作。如果Bean实现了InitializingBean接口,将调用afterPropertiesSet方法。如果Bean在Spring配置文件中配置了init-method属性,将自动调用其配置的初始化方法。如果Bean关联了BeanPostProcessor接口,将调用初始化方法postProcessAfterInitialization(Object obj,String s)方法,由于在Bean初始化结束时调用After方法,也可用于内存缓存技术。
以上完成了就可以使用该Bean,Bean的作用域是singleton,所以调用的是同一个Bean。
- 当Bean不在需要时进入销毁阶段,如果Bena实现了DisposableBean接口,则调用其实现的destroy方法将Spring中的Bean销毁。如果在配置文件中通过destroy-method属性制定了Bean的销毁方法,将调用其配置的销毁方法进行销毁。
Bean生命周期演示:
- 创建Bean的实现类
在src目录下创建life包,并创建BeanLife类,在BeanLife创建initMyself和destroyMyself方法,演示初始化和销毁过程。
public class BeanLife {
public void initMyself() {
System.out.println(this.getClass().getName() + "执行自定义的初始化方法");
}
public void destroyMyself() {
System.out.println(this.getClass().getName() + "执行自定义的销毁方法");
}
}
- 配置Bean
在Spring配置文件中使用实现类BeanLife配置一个id为beanLife的Bean
- 测试生命周期
在测试类中进行测试
public class SpringTest {
public static void main(String[] args) {
//初始化Spring容器的ClassPathXmlApplicationContext,加载配置文件
ClassPathXmlApplicationContext classPathXmlApplicationContext =new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("获取对象前");
BeanLife beanLife = (BeanLife) classPathXmlApplicationContext.getBean("beanLif");
System.out.println("获取对象后" + beanLife);
classPathXmlApplicationContext.close();
}
}
- 运行结果
可以看出,加载配置文件时执行了Bean的初始化方法initMyself,在获得对象后,关闭容器时,执行了Bean的销毁方法destroyMyself。
五、Bean的装配方式Bean的装配方式可以理解为将Bean依赖注入到Spring容器中,Bean的装配方式即Bean依赖注入的方式。
主要有:
基于xml配置的装配基于注解的装配自动装配 5.1 基于XML配置的装配
基于XML的依赖注入有两种方式
构造方法注入
setter方法注入
代码实例:
在src目录下创建assemble包,并新建ComplexUser类,演示构造方法注入和属性的setter方法注入
public class ComplexUser {
//不同数据类型的依赖注入
private String name;
private List hobbyList;
private Map residenceMap;
private Set aliasSet;
private String[] array;
public ComplexUser(String name,List hobbyList,Map residenceMap,Set aliasSet,String[] array){
super();
this.name = name;
this.hobbyList = hobbyList;
this.residenceMap = residenceMap;
this.aliasSet = aliasSet;
this.array = array;
}
public ComplexUser(){
super();
}
public void setName(String name) {
this.name = name;
}
public void setHobbyList(List hobbyList) {
this.hobbyList = hobbyList;
}
public void setResidenceMap(Map residenceMap) {
this.residenceMap = residenceMap;
}
public void setAliasSet(Set aliasSet) {
this.aliasSet = aliasSet;
}
public void setArray(String[] array) {
this.array = array;
}
@Override
public String toString() {
return "name=" + name + ";hobbyList=" + hobbyList + ";residenceMap=" +residenceMap +"; aliasSet="+ aliasSet + ";array=" + Arrays.toString(array);
}
}
- 配置文件中配置Bean
构造方法注入的配置:
sing
dance
running
user001
user002
user003
aaa
bbb
属性的setter方法注入的配置:
study
read
user001
user002
user003
ccc
ddd
- 测试类中测试
public class SpringTest {
public static void main(String[] args) {
//初始化Spring容器的ApplicationContext,加载配置文件
ApplicationContext applicationContext =new ClassPathXmlApplicationContext("applicationContext.xml");
//构造方法装配
ComplexUser user1 = (ComplexUser) applicationContext.getBean("user1");
System.out.println(user1);
//setter方法装配
ComplexUser user2 = (ComplexUser) applicationContext.getBean("user2");
System.out.println(user2);
}
}
- 测试结果
以上为构造函数和setter方法注入的装配方式结果。
5.2 基于注解的装配xml配置文件可以简单的装配Bean,但在大量的Bean需要装配的时候,会导致xml文件过于庞大,且不方便升级与维护,更多的使用注解(annotation)的当时装配Bean。
注解类型
| 注解 | 作用 |
|---|---|
| @Component | 该注解是一个泛化的概念,仅仅表示一个组件对象(Bean),可以作用在任何层次上。 |
| @Repository | 该注解用于将数据访问层(Dao)的类标识为Bean,即注解数据访问层Bean,功能与@Component相同,作用于类前面 |
| @Service | 该注解用于标注一个业务逻辑组件类(Service),功能与@Component相同,作用于类前面 |
| @Controller | 该注解用于标注一个控制器组件类(Spring MVC 的Controller),功能与@Component相同,作用于类前面 |
| @Autowired | 该注解可以对类的成员变量、方法及构造方法进行标注,完成自动装配的工作。通过使用@Autowired来消除setter和getter方法。默认按照Bean的类型进行装配。 |
| @Resource | 与@Autowired功能一样,区别在于该注解默认是按名称来装配注入的。即@Resource注解有两个属性–name和type。name属性指定Bena实例名称,即安装名称来装配注入;type属性指定Bean类型,即按照Bean的类型进行装配。 |
| @Qualifier | 该注解与@Autowired注解配合使用。当@Autowired注解需要安装名称来装配注入时需要和该注解一起使用,Bean的实例名称由@Qualifier注解的参数指定 |
| @Scope | 指定Bena的作用域 ,例如@Scope(scopeName = “singleton”) |
代码实例:
- 新建annotation包进行演练
创建Dao层,新建TestDao接口和实现类并使用@Repository注解标注为数据访问层
public interface TestDao {
public void save();
}
@Repository("testDao")
public class TestDaoImpl implements TestDao {
@Override
public void save() {
System.out.println("testDao save");
}
}
- 新建service包,并创建testService接口和实现类
public interface TestService {
public void save();
}
@Service
public class TestServiceImpl implements TestService {
@Resource(name = "testDao")
private TestDao testDao;
@Override
public void save() {
testDao.save();
System.out.println("testService save");
}
}
- 新建控制器controller层,并使用@Controller注解进行标识,并自动装配逻辑层的Bean。
//不指定Bean的名字,Spring默认给Bean取id名,取名方式为类名第一个字母小写即testController
@Controller
public class TestDao {
@Autowired
private TestService testService;
public void save(){
testService.save();
System.out.println("testController save");
}
}
为什么不指定Bean的名字,spring取类名首字母小写的作为Bean名字,大佬的源代码分析spring是如何给bean起名字的
- 配置文件进行Bean配置
xmlns:context="http://www.springframework.org/schema/context" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"
配置扫描注解
- 测试类中进行测试
public class SpringTest {
public static void main(String[] args) {
//初始化Spring容器的ApplicationContext,加载配置文件
ApplicationContext applicationContext =new ClassPathXmlApplicationContext("applicationContext.xml");
TestController testController = (TestController) applicationContext.getBean("testController");
testController.save();
}
}
- 测试结果
至此Bean的基础就复习就结束了。



