Spring中的Bean管理

Spring中的Bean管理

Spring IOC容器

Spring框架主要是通过Spring容器实现的,Spring提供了相应的API来管理Bean,最常用的是BeanFactory和ApplicationContext

BeanFactory接口

这个接口采用Java的工厂模式,这个接口提供了创建和管理Bean的方法

方法名称描述
getBean(String name)根据参数名称获取Bean
getBean(String name,Class <T>type)根据参数名称,参数类型来获取Bean
<T>T getBean(Class<T>requiredType)根据参数类型获取Bean
Object getBean(String name,Object…oegs)根据参数名称获取Bean
isTypeMatch(String name,Resolvable Typetype)判断是否有与参数名称、参数类型匹配的Bean
Class<T>getType(String name)根据参数名称获取类型
String[] getAliase(String name)根据实例的名称获取实例的别名数组
boolean containsBean(String name)根据Bean的名称判断Spring容器是否含有指定的Bean

ApplicationContext接口

该接口建立在BeanFactory接口的基础之上,丰富了BeanFactory接口的特性,添加了对国际化,资源访问,事件传播等方面的支持

这个接口可以为单例的Bean实行预初始化,并根据< property >元素执行setter方法,单例Bean可以直接使用,提升了程序获取Bean实例的性能

类名称描述
ClassPathXmlApplicationContext从类路径加载配置文件,实例化ApplicationContext接口
FileSystemXmlApplicationContext从文件系统加载配置文件,实例化ApplicationContext接口
AnnotationConfigApplicationContext从注解中加载配置文件,实例化ApplicationContext接口
WebApplicationContext从Web应用中使用,从相对于Web根目录的路径中加载配置文件,实例化ApplicationContex接口
ConfigurableWebApplicationContext扩展了WebApplicationContext类,可以通过读取XML配置文件的方式实例化WebApplicationContext接口

Bean配置

在Spring中XML配置文件的根元素是< beans >,包含< bean >子元素,每个子元素可以定义一个Bean,通过< bean >元素将Bean注册到Spring容器中

  • < bean >元素中的常用属性
    • id 唯一标识符,Spring容器对Bean的配置和管理通过id属性完成,装配Bean时也需要根据id值获取对象
    • name 可以为Bean指定多个名称
    • class 只当Bean的具体实现类,其属性为对象所属类的全路径
    • scope 设定Bean实例的作用范围
  • < bean >元素常用的子元素
    • < constructor-arg >可以为Bean的属性指定值,具有以下属性
      • index:用于设置构造参数的序号
      • type:用于指定构造参数类型
      • ref:用于指定参数值
      • value:用于指定参数值(参数值也可以通过ref和value的子元素指定)
    • < property >是调用Bean实例中的setter方法完成属性赋值,从而完成依赖注入
      • name:指定Bean实例中的属性名
      • ref:用于指定参数值
      • value:一样
    • ref:是上面两个元素的属性,用于指定Bean工厂中某个Bean实例的引用
    • value:用于指定一个常量值
    • < list > 用于指定Bean属性类型为List或数组
    • < set > 指定属性类型为Set
    • < map >同上
    • < entry > 该元素是< map >的子元素,用于设置一个键值对。< entry >元素的key属性用于指定字符串类型的键,用ref和value子元素指定< entry >元素的值,或者value-ref又或者value指定< entry > 元素的值

Bean的实例化

构造方法的实例化

构造方法实例化是☞Spring容器通过Bean对应类中默认的无参构造方法来实例化Bean

在类中自定义无参构造方法,在applicationBean1.xml文件中配置一个id为bean1的Bean,通过class属性指定对应的实现类为Bean1,创建测试文件进行测试,测试成功便表明Spring容器成功调用Bean1类的默认构造方法完成了实例化

package com.yjw;

public class Bean1 {
    public Bean1(){
        System.out.println("这是Bean1");
    }
}

<?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="bean1" class="com.yjw.Bean1"></bean>
</beans>

静态工厂实例化

使用静态工厂实例化Bean时,还要定义一个静态工厂类,用静态工厂类中的方法创建Bean实例,此时的Bean配置文件class属性指定的不再是Bean的实现类,而是定义的静态工厂类;还要使用< bean > 元素的factory-method属性指定所定义的静态工厂方法

bean元素配置

通过factory-method属性指定静态工厂方法

 <bean id="bean2" class="com.yjw.MyBean2Factory" factory-method="createBean"></bean>

创建MyBean2Factory类,定义静态方法用来创建Bean的实例

public class MyBean2Factory {
    public static Bean2 createBean(){
        return new Bean2();
    }
}

实例工厂实例化

就是直接创建 Bean实例;在XML配置文件中,不使用class属性指向Bean所指向的类,而是使用factory-bean属性指向为Bean配置的实例工厂,并用factory-method属性指定要调用的实例工厂方法

package com.yjw;

public class MyBean3Factory {
    public MyBean3Factory(){
        System.out.println("工厂实例化中:");
    }
    public Bean3 createBean(){
        return new Bean3();
    }
}

   <bean id="myBean3Factory" class="com.yjw.MyBean3Factory"></bean>
    <bean id="bean3" factory-bean="myBean3Factory" factory-method="createBean"></bean>

createBean方法时非静态的,所以要创建工厂的实例才能调用,所以创建了两个Bean,一个是工厂,另一个是Bean3的实例

Bean的作用域

Sprinag容器创建一个Bean实例时,可以为该Bean指定作用域,也就是Bean实例的有效范围;使用scope属性来指定作用域

  • singleton:单例模式。Spring容器只能存在一个共享的Bean实例,只要请求id或name与Bean的定义相匹配,就会返回Bean的同一个实例
  • prototype:原型模式:每次从容器请求bean时,都会产生一个新的实例
  • request:每个HTTP请求都会有一个Bean实例,该作用域只能基于Web的Spring ApplicationContext中使用
  • session:每个HttpSession请求都会有自己的Bean实例,该作用域只能基于Web的Spring ApplicationContext中使用
  • global session:限定一个Bean的作用域为Web应用(HttpSession)的声明周期,只有在Web中使用Spring时该作用域才有效

Bean的装配方式

也就是依赖的注入,分别有三种常见方式:基于XML装配,基于注解装配以及自动装配

基于XML的装配

也就是读取xml文件中的信息完成依赖注入,而基于XML的装配方式也有两种:setter方法注入和构造方法注入,之前笔记就有,我就不写了

基于注解装配

常用注解:

  • @Component:指定一个普通的Bean,可以作用于任何层次
  • @Controller:指定一个控制器组件Bean,将控制层的类标识为Spring中的Bean,功能上等同于@Component
  • @Service:指定一个业务逻辑组件Bean,用于将业务逻辑层的类标识为Bean,功能上也等同于第一个
  • @Repository:指定一个数据访问组件Bean,用于将数据访问层的类标识为Spring中的Bean功能上等同于第一个
  • @Scope:指定Bean实例的作用域
  • @Value:指定Bean实例的注入值
  • @Autowired:指定要自动装配的对象
  • @Resource:指定要注入的对象
  • @Qualifier:指定要自动装配的对象名称,通常域@Autowired联合使用
  • @PostConstruct:指定Bean实例完成初始化后调用的方法
  • @PreDestroy:指定Bean实例销毁前的方法

具体步骤:

  1. 导入依赖

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aop</artifactId>
                <version>5.2.8.RELEASE</version>
            </dependency>
    
  2. 创建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: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/context
        http://www.springframework.org/schema/context/spring-context.xsd">
        <context:component-scan base-package="com.yjw"/>
    </beans>
    
  3. 定义实体类

    package com.yjw.entity;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Component;
    
    @Component("user")
    @Scope("singleton")
    public class User {
        @Value("1")
        private int id;
        @Value("张三")
        private String name;
        @Value("123456")
        private String password;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public String toString(){
            return "id="+id+",name="+name+",password="+password;
        }
    }
    
    
  4. 定义DAO层

  5. 实现dao层

    package com.yjw.dao;
    
    import com.yjw.entity.User;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import org.springframework.stereotype.Repository;
    
    //使用注解,将数据访问层标识为Spring中的Bean
    @Repository("userDao")
    public class UserDaoImpl implements UserDao {
        public void save(){
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
            User user = (User)applicationContext.getBean("user");
            System.out.println(user);
            System.out.println("执行UserDaoImpl.save()");
        }
    }
    
  6. 定义Service层

  7. 实现Service层

    package com.yjw.service;
    
    import com.yjw.dao.UserDao;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    @Service("userService")
    public class UserServiceImpl implements UserService{
            //使用@Resource指定要注入的对象
            @Resource(name = "userDao")
            private UserDao userDao;
        public void save(){
            this.userDao.save();
            System.out.println("执行UserServiceImpl.save()");
        }
    }
    
  8. 定义Controller层

    package com.yjw.controller;
    
    import com.yjw.service.UserService;
    import org.springframework.stereotype.Controller;
    import javax.annotation.Resource;
    
    @Controller
    public class UserController {
        //注入userService
        @Resource(name = "userService")
        private UserService userService;
        public void save(){
            this.userService.save();
            System.out.println("执行UserController.save()");
        }
    }
    
    
  9. 定义测试类

    package com.yjw;
    
    import com.yjw.controller.UserController;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class AnnotationTest {
        public static void main(String[] args) {
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
            UserController userController =(UserController) applicationContext.getBean("userController");
            userController.save();
        }
    }
    
    

DAO(Data Access Object)数据访问层,负责与数据库进行交互,负责数据的增删改查操作

Service业务逻辑层:负责对业务逻辑进行处理,对数据进行加工和封装

Controller控制层:负责接收来自用于请求并调用相应的业务逻辑处理,将处理结果返回给用户

自动装配

Spring中的< bean >元素包含一个autowire属性,可以通过设置该属性实现Bean的自动装配

  • default:有< bean >的上级元素的default-autowire属性值确定
  • byName:根据bean元素id属性自动装配
  • byType:根据bean元素的数据类型(Type)自动装配,如果一个Bean的数据类型兼容另一个Bean中的数据类型,则自动装配
  • construct:根据构造函数的数据类型进行byType模式自动装配
  • no:默认值,不使用自动装配,Bean依赖必须通过< ref >元素或ref属性定义

Bean的生命周期

Bean的生命周期指的时Bean实例被创建,初始化和销毁的过程。在Bean的两种作用域中,singleton和prototype中,前者Spring容器可以管理Bean的生命周期,控制Bean的创建初始化和销毁;在prototype作用域中,Spring容器只会创建实例,不会管理其生命周期

因此在Bean的生命周期中有两个节点非常重要,一个是Bean实例刚刚完成初始化,另一个时Bean实例被销毁之前,这两个时间点通常需要完成一些指定的操作;因此需要对这两个结点进行监控;可以使用注解来完成

@PostConstruct:指定Bean实例完成初始化后调用的方法,用于监控Bean对象初始化的节点
@PreDestroy:指定Bean实例销毁前的方法,用于监控Bean对象的销毁节点

监控时可以将这两个注解标注在特定的方法上

总结

  • 了解Bean的配置以及,以及bean元素的常用属性以及子属性

  • 了解Bean实例化的三种方法

    • 使用构造方法进行Bean的实例化
    • 创建工厂类,定义静态工厂方法,bean配置指向静态工厂类和静态工厂方法
    • 创建工厂的Bean实例,在bean配置中在用相应属性指向工厂的Bean以及实例工厂方法
  • 了解Bean的作用域

  • 了解Bean的装配方式

    • 基于XML装配:也就是setter方法注入以及构造方法注入
    • 注解装配,了解相关注解的作用,用相关注解来注册Bean以及注入数值,并构建dao层,service层以及controller层
    • 自动装配
  • Bean的生命周期

    使用相关注解来监控Bean实例初始化以及被被销毁前的动作