前言
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默认是单例模式。
- singleton(单例 ): 全局有且仅有一个实例。
- prototype(多例): 每次获取Bean的时候会有一个新的实例。
- request : request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效。
- session :session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效。
- 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注解,如果想了解请自行跳转。ω