spring-Bean

Spring中的bean可以配置为单例或原型作用域,单例bean在整个容器内只有一个实例,而原型bean每次请求都会创建新实例。bean的生命周期包括创建、属性设置、初始化、后置处理、使用和销毁。此外,通过FactoryBean可以创建更复杂的对象。自动装配允许Spring根据类型或名称自动填充bean的依赖。
摘要由CSDN通过智能技术生成

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方法、构造方法、构造方法形参上。

@Resource注解属于JDK扩展包,所以不再JDK中,需要额外引入以下依赖

<dependency>
  <groupId>jakarta.annotation</groupId>
  <artifactId>jakarta.annotation-api</artifactId>
  <version>2.1.1</version>
</dependency>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值