Spring可以做很多事情,为企业级开发提供了丰富的功能,但是这些功能都依赖于它的两个核心特性:依赖注入(DI)或控制反转(IOC)和面向切面编程(AOP)。如果说Spring IOC容器将开发人员从对Bean(实例)的管理的繁重任务中脱离出来,那么Spring提供的注解则将开发人员从Spring中繁复的xml配置中解脱出来。
Spring为我们提供了很多注解,用于将我们自己写的组件交给Spring IOC容器管理,比如:我们可以使用@Controller注解标注该类为一个控制器,使用@Service标注一个类为业务逻辑类,@Repository标注一个类为数据库访问类,@Component标注一个类为组件,@Configuration标注该类是一个配置类。但是对于第三方框架或者jar包,这些组件就无能为力了,不过Spring为我们准备了其他注解,将第三方无法使用上述注解的类交给Spring管理,比如:@Bean,@Import等
@Bean注解的使用
1.@Bean注解用于@Configration注解的类的方法上,用于创建一个Spring IOC管理的Bean,默认情况下,被创建的bean在Spring中的名称为方法名,如下代码所示,创建的bean的名称为printComponent:
@Bean
public PrintComponent printComponent() {
return new PrintComponent();
}
2.Spring为@Bean注解提供了 value和name属性,它们的类型为字符串数组,我们可以使用这两个属性为该bean指定名称,但是这两个直接不能同时使用,只能使用其中的一个。 如果指定了多个名称,在使用getBeanDefinitionNames方法打印Bean名称时,只打印第一个名称。代码示例如下:
@Bean(name="print")
public PrintComponent printComponent() {
return new PrintComponent();
}
//一个bean实例两个名称,使用context.getBean("printComponent")和context.getBean("print")获取的是一个实例
@Bean(name={"print","printComponent"})
public PrintComponent printComponent() {
return new PrintComponent();
}
//一个bean实例两个名称,使用context.getBean("printComponent")和context.getBean("print")获取的是一个实例
@Bean(value={"print1","printComponent2"})
public PrintComponent printComponent() {
return new PrintComponent();
}
将Bean交给Spring IOC之后,由IOC负责对Bean的实例化,可能我们需要在Bean实例化之后(构造方法调用之后)和容器关闭之前做一些操作。此时,我们可以使用@Bean注解的initMethod方法为该实例指定一个初始化方法,使用destroyMethod为该实例指定一个销毁方法。如下代码,initMethod方法会在实例化之后调用,destoryMethod方法会在IOC容器销毁时被调用
public class PrintComponent {
public PrintComponent() {
System.out.println("构造方法");
}
public void initMethod() {
System.out.println("打印之前,检查是否准备好石墨和纸张");
}
public void printContent() {
System.out.println("打印中");
}
public void destoryMethod() {
System.out.println("报警:已经打印完成,可以取出打印的纸张");
}
}
@Bean(value="print",initMethod ="initMethod", destroyMethod="destoryMethod")
public PrintComponent printComponent() {
return new PrintComponent();
}
@Scope注解
默认情况下交给Spring管理的Bean都是单例的,如果我们想使用多例模式的Bean,则可以使用@Scope注解。@Scope注解用于为Bean指定作用域。Spring中的Bean有四种作用域:默认为singleton:单实例的(默认值):ioc容器启动会调用方法创建对象放到ioc容器中。以后每次获取就是直接从容器(map.get())中拿,prototype:多实例的:ioc容器启动并不会去调用方法创建对象放在容器中。每次获取的时候才会调用方法创建对象;request:同一次请求创建一个实例,session:同一个session创建一个实例。值得注意的是如果@Bean中包含initMethd属性和destroyMethod属性,多例的Bean只会指定initMethod方法中指定的方法,destroyMethod中指定的方法不会执行。
@Scope("prototype")
@Bean(value="print")
public PrintComponent printComponent() {
return new PrintComponent();
}
@Lazy注解
默认情况下Spring在容器启动的时候创建对象;如果我们不想让容器启动的时候就创建对象,而是在获取实例的时候才创建对象,则可以使用@Lazy注解:
@Lazy
@Bean(value="print", initMethod = "initMethod",destroyMethod="destoryMethod")
public PrintComponent printComponent() {
return new PrintComponent();
}
@PostConstruct与@PreDestroy
前面我们提到我们可以使用@Bean注解的initMethod方法为该实例指定一个初始化方法,使用destroyMethod为该实例指定一个销毁方法。这两个方法分别在实例创建之后和容器销毁之前被调用,除此之外,我们还可以在Bean的方法上标注@PostConstruct和@PreDestroy注解。他们是JSR250提供的两个注解,@PostConstruct在实例创建之后被调用,@PreDestroy在容器被销毁之前调用。代码如下:
public class PrintComponent {
public PrintComponent() {
System.out.println("构造方法");
}
@PostConstruct
public void initMethod() {
System.out.println("打印之前,检查是否准备好石墨和纸张");
}
public void printContent() {
System.out.println("打印中");
}
@PreDestroy
public void destoryMethod() {
System.out.println("报警:已经打印完成,可以取出打印的纸张");
}
}
@Bean(value="print")
public PrintComponent printComponent() {
return new PrintComponent();
}