Bean
Spring Bean是由Spring IoC容器管理的对象实例,也是Spring框架的基本组件之一。
Bean可以是任何一个普通的Java对象,也可以是第三方库中的对象,例如Hibernate SessionFactory或MyBatis SqlSessionFactory。
Spring Bean的创建、组装和管理是由Spring IoC容器负责的。在容器中注册一个Bean后,容器负责创建Bean的实例、管理Bean的生命周期,以及处理Bean之间的依赖关系。通过 Spring 容器,可以实现对象之间的松耦合,便于测试、模块化开发、重用等。
在Spring中,Bean是通过配置文件或注解来定义的。
配置文件通常是XML或Java配置类,通过声明Bean的类名、作用域、依赖关系、属性值等信息来定义Bean。
注解则是通过在Bean类上添加特定的注解来定义Bean。
无论是XML配置文件还是注解,都需要被Spring IoC容器加载和解析,以创建Bean的实例并放入容器中。
@Component
在运行时,Spring会找到所有使用@Component或其派生类进行注释的类,并将它们用作bean定义。
查找带注释的类的过程称为组件扫描。
@Conpontent衍生物是Spring构造型注释,它们本身用@Component注释。
@Component衍生列表包括:
@Service@Repository@Controller
注释之间的区别纯粹是信息性的。它们允许你根据通用职责轻松对bean进行分类。
你可以使用这些注释将bean类标记为特定应用程序层的成员,Spring框架会将它们全部视为@Components。
Bean的作用域
Spring中Bean的作用域通常有:
singleton:单例,这种bean范围是默认的,这种范围确保不管接受到多少个请求,每个容器中只有一个bean的实例,单例的模式由BeanFactory自身来维护。prototype:原形,范围与单例范围相反,每次获取都会创建一个新的bean实例,连续getBean()两次,是不同的Bean实例。request(Web应用使用):请求,在请求bean范围内会每一个来自客户端的网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收session(Web应用使用):会话,与request范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。application/global-session(Web应用使用):全局会话,在一个全局的Http Session中,容器会返回该bean的同一个实例,仅在使用portlet context时有效。websocket(Web应用使用):网络通信,在WebSocket会话范围内会创建一个新的bean。
Bean的生命周期
Spring上下文中的Bean生命周期如下:
- 实例化
Bean:- 对于
BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。 - 对于
ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。
- 对于
- 设置对象属性(依赖注入):实例化后的对象被封装在
BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息以及通过BeanWrapper提供的设置属性的接口完成依赖注入。 - 处理
Aware接口:Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:- 如果这个
Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的就是Spring配置文件中Bean的id值; - 如果这个
Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。 - 如果这个
Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;
- 如果这个
BeanPostProcessor:如果想对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。InitializingBean与init-method:- 如果
Bean在Spring配置文件中配置了init-method属性,则会自动调用其配置的初始化方法。 - 如果这个
Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法; 由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术
- 如果
以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。
DisposableBean:当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;destroy-method:如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
Bean注入的实现方式
早期的开发基本是基于xml的配置,目前大部分都是基于注解的配置
基于xml注入bean
构造器注入
/*带参数,方便利用构造器进行注入*/
public ADaoImpl(String msg){
this.msg = msg;
}
xml配置
<bean id="ADaoImpl" class="com.ADaoImpl">
<constructor-arg value="msg"></constructor-arg>
</bean>
setter方法注入
public class AId {
private int id;
public int getId() { return id; }
public void setId(int id) { this.id = id; }
}
xml配置
<bean id="AId" class="com.AId">
<property name="id" value="111"></property>
</bean>
静态工厂注入
静态工厂顾名思义,就是通过调用静态工厂的方法来获取自己需要的对象,为了让spring管理所有对象,
我们不能直接通过工程类.静态方法()来获取对象,而是依然通过spring注入的形式获取:
public class DaoFactory { //静态工厂
public static final FactoryDao getStaticFactoryDaoImpl(){
return new StaticFacotryDaoImpl();
}
}
public class SpringAction {
private FactoryDao staticFactoryDao; //注入对象
//注入对象的 set 方法
public void setStaticFactoryDao(FactoryDao staticFactoryDao) {
this.staticFactoryDao = staticFactoryDao;
}
}
xml配置
<!--factory-method="getStaticFactoryDaoImpl"指定调用哪个工厂方法-->
<bean name="springAction" class=" SpringAction" >
<!--使用静态工厂的方法注入对象,对应下面的配置文件-->
<property name="staticFactoryDao" ref="staticFactoryDao"></property>
</bean>
<!--此处获取对象的方式是从工厂类中获取静态方法-->
<bean name="staticFactoryDao" class="DaoFactory"
factory-method="getStaticFactoryDaoImpl"></bean>
实例工厂
实例工厂的意思是获取对象实例的方法不是静态的,所以你需要首先new工厂类,再调用普通的实例方法:
public class DaoFactory { //实例工厂
public FactoryDao getFactoryDaoImpl(){
return new FactoryDaoImpl();
}
}
public class SpringAction {
private FactoryDao factoryDao; //注入对象
public void setFactoryDao(FactoryDao factoryDao) {
this.factoryDao = factoryDao;
}
}
xml配置
<bean name="springAction" class="SpringAction">
<!--使用实例工厂的方法注入对象,对应下面的配置文件-->
<property name="factoryDao" ref="factoryDao"></property>
</bean>
<!--此处获取对象的方式是从工厂类中获取实例方法-->
<bean name="daoFactory" class="com.DaoFactory"></bean>
<bean name="factoryDao" factory-bean="daoFactory"
factory-method="getFactoryDaoImpl"></bean>
基于注解注入bean
声明bean
@Component:通用的注解,可标注任意类为Spring组件。如果一个Bean不清楚属于哪一层,可以使用@Component注解标注。@Repository: 对应持久层即Dao层,主要用于数据库相关操作。@Service: 对应服务层,主要涉及一些复杂的逻辑,需要用到Dao层。@Controller: 对应Spring MVC控制层,主要用户接受用户请求并调用Service层返回数据给前端。
@Component和@Bean的区别
@Component注解作用于类,而@Bean注解作用于方法。@Component通常是通过类路径扫描来⾃动侦测以及⾃动装配到Spring容器中(我们可以使用@ComponentScan注解定义要扫描的路径从中找出标识了需要装配的类⾃动装配到Spring的bean容器中)。@Bean注解通常是我们在标有该注解的方法中定义产生这个bean,@Bean告诉了Spring这是某个类的实例,当我需要用它的时候还给我。@Bean注解比@Component注解的⾃定义性更强,而且很多地方我们只能通过@Bean注解来注册bean。 比如当我们引用第三方库中的类需要装配到Spring容器时,则只能通过@Bean来实现。
使用Bean
Spring内置的@Autowired以及JDK内置的@Resource和@Inject都可以⽤于注入Bean。
一般都是使用@Autowired和@Resource
5种不同方式的自动装配
Spring装配包括手动装配和自动装配,手动装配是有基于xml装配、构造方法、setter方法等
自动装配有五种自动装配的方式,可以用来指导Spring容器用自动装配方式来进行依赖注入。
no:默认的方式是不进行自动装配,通过显式设置ref属性来进行装配。byName:通过参数名自动装配,Spring容器在配置文件中发现bean的autowire属性被设 置成byName,之后容器试图匹配、装配和该bean的属性具有相同名字的bean。byType:通过参数类型自动装配,Spring容器在配置文件中发现bean的autowire属性被 设置成byType,之后容器试图匹配、装配和该bean的属性具有相同类型的bean。如果有多个bean符合条件,则抛出错误。constructor:这个方式类似于byType,但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常。autodetect:首先尝试使用constructor来自动装配,如果无法工作,则使用byType方式。