Bean
在 Spring 中,构成应用程序主干并由Spring IoC容器管理的对象称为bean。bean是一个由Spring IoC容器实例化、组装和管理的对象。
基本概念
bean的作用域
概念:在spring中可以通过配置bean标签的scope属性来指定bean的作用域范围。
取值 | 含义 | 创建对象的时机 |
---|---|---|
singleton(默认) | 在IoC容器中,这个bean的对象始终为单实例 | IOC容器初始化 |
prototype | 这个bean在IOC容器中有多个实例 | 获取bean时 |
如果在WebApplicationContext环境下还会有另外几个作用域(不常用)
取值 | 含义 |
---|---|
request | 在一个请求范围内有效 |
session | 在一个会话范围内有效 |
测试bean的作用域
singleton
创建Orders对象
public class Orders {
}
编写配置文件
<!--通过scope属性配置单实例或者多实例对象,singleton表示单实例对象 prototype表示多实例-->
<bean id="orders" class="com.louis.scope.Orders" scope="singleton"></bean>
测试
@Test
public void testScope(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-scope.xml");
Orders orders = applicationContext.getBean("orders", Orders.class);
logger.info("orders" + orders);
Orders orders1 = applicationContext.getBean("orders", Orders.class);
logger.info("orders1" + orders1);
logger.info("单实例对象判断两次获得的是否相等" + (orders == orders1));
}
/*
* [2023-06-23 15:54:12:661] [INFO] - TestBeanById.testScope(TestBeanById.java:212) - orderscom.louis.scope.Orders@e84a8e1
[2023-06-23 15:54:12:664] [INFO] - TestBeanById.testScope(TestBeanById.java:214) - orders1com.louis.scope.Orders@e84a8e1
[2023-06-23 15:54:12:665] [INFO] - TestBeanById.testScope(TestBeanById.java:215) - 单实例对象判断两次获得的是否相等true
* */
prototype
配置文件
<bean id="ordersOther" class="com.louis.scope.Orders" scope="prototype"></bean>
测试
@Test
public void testScopePrototype(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-scope.xml");
Orders ordersOther = applicationContext.getBean("ordersOther", Orders.class);
logger.info("ordersOther" + ordersOther);
Orders ordersOther01 = applicationContext.getBean("ordersOther", Orders.class);
logger.info("ordersOther01" + ordersOther01);
logger.info("多实例对象判断两次获得的是否相等" + (ordersOther == ordersOther01));
}
/*
* [2023-06-23 16:01:18:960] [INFO] - TestBeanById.testScopePrototype(TestBeanById.java:228) - ordersOthercom.louis.scope.Orders@2e554a3b
[2023-06-23 16:01:18:964] [INFO] - TestBeanById.testScopePrototype(TestBeanById.java:230) - ordersOther01com.louis.scope.Orders@3a0d172f
[2023-06-23 16:01:18:964] [INFO] - TestBeanById.testScopePrototype(TestBeanById.java:231) - 多实例对象判断两次获得的是否相等false
* */
bean的生命周期
1、bean对象创建(调用无参构造方法)
2、给bean对象设置相关属性
3、bean后置处理器(初始化之前)
4、bean对象的初始化操作(调用指定的初始化方法)
5、bean后置处理器(初始化之后)
6、bean对象创建完成,可以使用
7、bean对象销毁(配置指定销毁的方法)
8、IOC容器关闭
测试bean的生命周期
User
package com.louis.beanLife;
/**
* @author XRY
* @date 2023年06月23日16:10
*/
public class User {
private String name;
public User() {
System.out.println("1、创建bean对象、调用无参数构造");
}
public User(String name) {
this.name = name;
}
//初始化方法
public void initMethod(){
System.out.println("4、bean对象初始化,调用指定的初始化方法");
}
//销毁方法
public void destroyedMethod(){
System.out.println("7、bean对象的销毁,调用指定的销毁的方法");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("2、给bean对象设置属性值");
this.name = name;
}
}
编写bean的后置处理器类
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("3、bean的后置处理器,在初始化之前执行");
System.out.println(beanName+"::"+bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("5、bean的后置处理器,在初始化之后执行");
System.out.println(beanName + "::" + bean);
return bean;
}
}
配置文件
<?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.xsd">
<bean id="testBeanLife" class="com.louis.beanLife.User" scope="singleton" init-method="initMethod" destroy-method="destroyedMethod">
<property name="name" value="Louis"></property>
</bean>
<!--bean的后置处理器要放入IOC容器中才会生效-->
<bean id="myBeanPost" class="com.louis.beanLife.MyBeanPost"></bean>
</beans>
测试
@Test
public void testBeanLife(){
//当需要销毁的时候,我们需要创建ClassPathXmlApplicationContext对象,Application对象中没有相关的销毁方法
ClassPathXmlApplicationContext applicationContext = new
ClassPathXmlApplicationContext("bean-life.xml");
User user = applicationContext.getBean("testBeanLife", User.class);
System.out.println("6、bean对象创建完成,可以使用");
logger.info("user" + user);
applicationContext.close();
}
/*
1、创建bean对象、调用无参数构造
2、给bean对象设置属性值
3、bean的后置处理器,在初始化之前执行
testBeanLife::User{name='Louis'}
4、bean对象初始化,调用指定的初始化方法
5、bean的后置处理器,在初始化之后执行
testBeanLife::User{name='Louis'}
6、bean对象创建完成,可以使用
[2023-06-23 16:47:46:915] [INFO] - TestBeanById.testBeanLife(TestBeanById.java:247) - userUser{name='Louis'}
7、bean对象的销毁,调用指定的销毁的方法
* */
FactoryBean
简介
FactoryBean是Spring提供的一种整合第三方框架的常用机制,它和普通的bean不相同,配置一个FactoryBean类型的bean,在获取bean的时候得到的并不是一class属性中配置的这个类的对象,而是getObject()方法的返回值。通过这种机制,Spring可以帮我们把复杂组件创建的详细过程和繁琐细节屏蔽起来,只展示最简洁的使用界面。
使用步骤
1、创建实体类
使用上面的实体类User
2、创建类MyFactoryBean并实现接口
package com.louis.factorybean;
import org.springframework.beans.factory.FactoryBean;
/**
* @author XRY
* @date 2023年06月25日8:49
*/
public class MyFactoryBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
3、编写配置文件
<?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.xsd">
<bean id="myFactoryBean" class="com.louis.factorybean.MyFactoryBean"></bean>
</beans>
4、测试
@Test
public void testMyFactoryBean(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-factorybean.xml");
logger.info("myFactoryBean" + applicationContext.getBean("myFactoryBean"));
}
/*[2023-06-25 09:02:09:063] [INFO] - TestBeanById.testMyFactoryBean(TestBeanById.java:266) - myFactoryBeancom.louis.factorybean.User@5ee2b6f9\n*/
Bean管理
基于xml自动装配
根据指定的策略,在IOC容器中匹配某一个bean,自动为指定的备案中所依赖的类类型或接口类型属性赋值
示例
1、准备
创建controller、service和dao层,编写它们的接口和实现类,在controller中定义service类型的属性,生成属性的set方法,在service定义dao类型属性并生成set方法。
controler
public class UserController {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public void addUser(){
System.out.println("我是controller");
//调用service的方法
userService.addUserService();
//原始方法:Controller调用service
// UserService userService = new UserServiceImpl();
// userService.addUserService();
}
}
service
public interface UserService {
public void addUserService();
}
impl
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void addUserService() {
System.out.println("我是UserService");
//调用方法实现
userDao.addUserDao();
//原始方法调用实现
// UserDao userDao = new UserDaoImpl();
// userDao.addUserDao();
}
}
dao
public interface UserDao {
public void addUserDao();
}
daoimpl
public class UserDaoImpl implements UserDao {
@Override
public void addUserDao() {
System.out.println("我是UserDao");
}
}
2、编写配置文件
<?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.xsd">
<bean id="controller" class="com.louis.autoFill.controller.UserController"
autowire="byType"></bean>
<bean id="service" class="com.louis.autoFill.service.impl.UserServiceImpl"
autowire="byType"></bean>
<bean id="dao" class="com.louis.autoFill.dao.impl.UserDaoImpl"
></bean>
</beans>
3、测试
@Test
public void testAutoFill(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-auto.xml");
UserController controller = applicationContext.getBean("controller", UserController.class);
controller.addUser();
}
/*我是controller
我是UserService
我是UserDao
*/
使用细节:
使用bean标签的autowire属性设置自动装配效果,
自动装配方式byType
<bean id="controller" class="com.louis.autoFill.controller.UserController"
autowire="byType"></bean>
<bean id="service" class="com.louis.autoFill.service.impl.UserServiceImpl"
autowire="byType"></bean>
<bean id="userDao" class="com.louis.autoFill.dao.impl.UserDaoImpl"
></bean>
byType
:表示根据类型匹配IOC容器中的某个兼容类型的bean,为属性自动赋值
若IOC中没有
任何一个兼容类型的bean能够为属性赋值,则该属性不装配,值为默认值null若在IOC中,有多个
兼容类型的bean能够为属性赋值,则抛出NoUniqueBeanDefinitionException
自动装配byName
<bean id="controller" class="com.louis.autoFill.controller.UserController"
autowire="byName"></bean>
<bean id="userService" class="com.louis.autoFill.service.impl.UserServiceImpl"
autowire="byName"></bean>
<bean id="userDao" class="com.louis.autoFill.dao.impl.UserDaoImpl"
></bean>
byName
:将自动装配的属性的属性名,作为bean的id在IOC容器中匹配相对应的bean进行赋值
需要注意的是属性的名称和id的名称必须保持一致
基于注解方式
从java5开始,java增加了对注解(Annotation)的支持,它是代码中的一种特殊标记,可以在编译、类加载和运行时被读取,执行相应的处理。开发人员可以通过注解在不改变原有代码的和逻辑的情况下,在代码中嵌入补充信息。我们可以使用注解来实现自动装配,简化Spring的xml配置。
格式
:@注解名称(属性1=属性值…),它可以使用在类、属性和方法上面。
步骤:
1、引入Spring依赖
2、开启组件扫描
spring默认不适用注解装配bean,因此我们需要在spring的xml配置中,通过context:component-scan元素开启spring beans的自动扫描功能,开启后,spring会自动扫描指定的包(base-package属性设置)及其子包下的所有类,如果使用了@Component注解,就将该类装配到容器中。在使用context:component-scan元素开启自动扫描功能前,首先要在xml配置的一级标签<beans>中添加context相关的约束。
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--开启组件扫描-->
<context:component-scan base-package="com.louis"></context:component-scan>
</beans>
组件扫描的方式
①最基本方式
<context:component-scan base-package="com.louis"></context:component-scan>
②指定要排除的组件
<context:component-scan base-package="com.louis">
<!--context:exclude-filter标签指定排除规则-->
<!--
type:设置排除或包含的依据
type="annotation",根据注解排除,expression中设置要排除的注解的全类名
type="assignable",根据类型排除,expression中设置要排除的类型的的全类名
-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
③仅扫描指定组件
<context:component-scan base-package="com.louis">
<!--context:include-filter标签指定在原有扫描规则的基础上追加的规则-->
<!--
type:设置排除或包含的依据
-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
3、使用注解定义bean
spring提供了多个注解,这些注解可以直接标注在java类上,将他们定义成Spring Bean。
@Component(value="user")//相当于<bean id="user" class="..."></bean>,其中value可以不写,在不屑的时候就是默认类的首字母小写
//@Repository(value="user")
//@Service(value="user")
//@Controller(value="user")
public class User {
public void testUser(){
System.out.println("我是User类");
}
}
注解 | 说明 |
---|---|
@component | 该注解用于描述Spring中的Bean,它是一个泛化的概念,仅仅表示容器中的一个组件(bean),并且可以作用在应用的任何层次,例如:service层、dao层等,使用时,只需要将该类注解标注在相应类上即可。 |
@Repository | 该注解用于将数据访问层(Dao层)的类标识为Spring中的Bean,其功能与@Component相同 |
@Service | 该注解通常作用在业务层(Service层),用于将业务层的类标识为Spring中的Bean,其功能与@Component相同 |
@Controller | 该注解通常作用在控制层(如SpringMVC的Controller),用于将控制层的类标识为Spring中的Bean,其功能与@Component相同。 |
4、依赖注入
@AutoWired注入
单独使用@AutoWired注解,默认根据类型装配(默认时byType)
它可以使用在构造方法、方法、形参、属性和注解上。该注解有一个required属性,默认值是true,表示注入的时候要求被注入的bean必须是存在的,如果不存在则会报错,如果required属性设置为false,表示注入的Bean存在或者不存在都没有关系。
第一种方式:属性注入
@Autowired //会根据类型找到对应的对象,完成注入
private UserDao userDao;
第二种方式:set注入
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
第三种方式:构造方法注入
private UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
第四种方式:形参上进行注入
private UserService userService;
public UserController(@Autowired UserService userService) {
this.userService = userService;
}
第五种方式:只有一个构造函数,可以不使用注解
private UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
第六种方式:@Autowired注解和@Qualifier注解联合使用
@Autowired默认是根据类型进行匹配,@Qualifier则默认是根据名称进行匹配,可以用于注入有多个实现类的情况。
@Autowired
@Qualifier(value = "userDaoOtherImpl")
private UserDao userDao;
@Resource注入
@Resource注解也可以完成属性注入,他和@Autowired的区别:
@Resource注解时JDK扩展包中的,属于JDK的一部分。所以该注解是标准注解,更加具有通用性。
@Autowired注解是Spring框架自己的
@Resource注解默认根据名称装配byName,未指定name时,使用属性名作为name.通过name找不到的话会自动启动通过来行byType装配
@Autowired注解默认根据类型装配byType,如果象根据名称装配,需要配合@Qulifier注解一起使用
@Resource注解用在属性、set方法上
@Autowired注解用在属性、set方法、构造方法、构造方法形参上。文章来源:https://www.toymoban.com/news/detail-576374.html
@Resource注解属于JDK扩展包,所以不再JDK中,需要额外引入以下依赖文章来源地址https://www.toymoban.com/news/detail-576374.html
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>
到了这里,关于spring-Bean的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!