欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring中的@Bean注解

程序员文章站 2022-03-03 11:23:54
...
前言

Spring中最重要的概念IOC和AOP,实际围绕的就是Bean的生成与使用。

关于IOC注解分为两类:

1、一类是使用Bean,即是把已经在xml文件中配置好的Bean拿来用,完成属性、方法的组装;比如@Autowired , @Resource,可以通过byTYPE(@Autowired)、byNAME(@Resource)的方式获取Bean;

2、一类是注册Bean,@Component , @Repository , @ Controller , @Service , @Configration这些注解都是把你要实例化的对象转化成一个Bean,放在IoC容器中,等你要用的时候,它会和上面的@Autowired , @Resource配合到一起,把对象、属性、方法完美组装。

@Bean注解

Spring的@Bean注解用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理。产生这个Bean对象的方法Spring只会调用一次,随后这个Spring将会将这个Bean对象放在自己的IOC容器中。默认添加的Bean的类型是方法的返回值,id是方法的名字。

实体类:

public class Person {
    private String name;
    private Integer age;

    public Person() {
    }

    public Person(String name, Integer age) {
    this.name = name;
    this.age = age;
    }
    
    public void init() {
        System.out.println("init ............");
    }
    
    public void destroy() {
        System.out.println(" destroy ...............");
    }

    // 省略 getter setter 方法

    // 省略 toString 方法
}

JavaConfig配置类:

@Configuration
public class MyConfig {

    @Bean
    public Person person() {
        return new Person("czx", 23);
    }

}

测试代码:

@Test
public void test() {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanConfig.class);
    Person person = ctx.getBean(Person.class);
    System.out.println(person);
}

输出结果:

Person{name='czx', age='23'}

@Bean 注解的属性

属性 作用
value 为bean起一个名字 默认方法的名字(同name)
name 为bean起一个名字 默认方法的名字(同value)
autowire 是否对该bean的属性实行自动装配
initMethod 初始化方法
destroyMethod 销毁方法

autowire属性的三种取值:
Autowire.NO (默认设置)
Autowire.BY_NAME
Autowire.BY_TYPE
指定 bean 的装配方式, 根据名称 和 根据类型 装配, 一般不设置,采用默认即可。

initMethod属性和destroyMethod的使用:

@Configuration
public class BeanConfig {

    @Bean(initMethod = "init",destroyMethod = "destroy")
    public Person person() {
        return new Person("czx", 23);
    }
}

如果 bean 是单例:在IoC容器启动时创建 bean 对象调用 bean 的初始化方法, 直接指定方法名称即可,不用带括号。bean 的销毁方法, 在调用 IoC 容器的 close() 方法时,会执行到该属性指定的方法。

如果 bean 是多例:在IoC容器启动时不创建 bean 对象,在使用时才创建bean 对象调用 bean 的初始化方法,并且IoC 容器不再会管理 bean 的声明周期,不会在调用 bean 的销毁方法。

通过上述方法创建的bean是单例的。可以使用@Scope注解改变bean的声明周期。

@Scope注解

@Scope注解是Ioc容器中的一个作用域,在 Spring IoC 容器中具有以下几种作用域:基本作用域singleton(单例)、prototype(多例),Web 作用域(reqeust、session、globalsession)。@scope默认是单例模式。

  1. singleton(单例 ): 全局有且仅有一个实例。
  2. prototype(多例): 每次获取Bean的时候会有一个新的实例。
  3. request : request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效。
  4. session :session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效。
  5. globalsession : global session作用域类似于标准的HTTP Session作用域,不过它仅仅在基于portlet的web应用中才有意义。

单例JavaConfig配置类:

@Configuration
public class MyConfig {

    @Bean
    @Scope(value="singleton")
    public Person person() {
        return new Person("czx", 23);
    }

}

单例测试类:

@Test
public void test() {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanConfig.class);
    Person person1 = ctx.getBean(Person.class);
    Person person2 = ctx.getBean(Person.class);
    System.out.println(person1 == person2);
}

单例结果:

true

多例JavaConfig配置类:

@Configuration
public class MyConfig {

    @Bean
    @Scope(value="prototype")
    public Person person() {
        return new Person("czx", 23);
    }

}

多例测试类:

@Test
public void test() {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanConfig.class);
    Person person1 = ctx.getBean(Person.class);
    Person person2 = ctx.getBean(Person.class);
    System.out.println(person1 == person2);
}

多例结果:

false

Spring默认的类型也是singleton,singleton虽然保证了全局是一个实例,对性能有所提高,但是如果实例中有非静态变量时,会导致线程安全问题,共享资源的竞争。当设置为prototype时每次连接请求,都会生成一个bean实例,也会导致一个问题,当请求数越多,性能会降低。

单例在IoC容器启动时就创建bean对象,如果想像多例一样在使用的时候再创建bean对象能办到吗?我们可以使用@Lazy注解实现懒加载。

@Lazy注解

懒加载只针对单实例bean,对于单实例bean默认在容器启动的时候创建对象。标注@Lazy后,容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化;

@Configuration
public class MyConfig {

    @Bean
    @Scope
    @Lazy
    public Person person() {
        return new Person("czx", 23);
    }

}

在使用@Bean注解的同时也经常使用@Value注解,如果想了解请自行跳转。ω