@Configuration的使用
@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。 @Configuration基于 @Component,意味着配置类自身就是个bean。
AnnotationConfigApplicationContext、AnnotationConfigWebApplicationContext会扫描 @Configuration注解,
并生成导入的 @bean对应的 BeanDefinition对象。
使用 @Configuration有以下几点注意
- @Configuration不可以是final类型;
- @Configuration不可以是匿名类;
- 嵌套的configuration必须是静态类(静态内部类)。
第一章:@Configuation加载Spring方法
@Configuration标注在类上,则配置类相当于作为spring配置文件中的 beans,作用为:配置spring容器(应用上下文)
import org.springframework.context.annotation.Configuration;
@Configuration
public class TestConfiguration {
public TestConfiguration() {
System.out.println("TestConfiguration容器启动初始化。。。");
}
}
配置类相当于applicationContext.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" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
default-lazy-init="false">
</beans>
通过配置类启动spring容器,用到 AnnotationConfigApplicationContext (注解配置上下文)加载配置类,代码如下
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class TestMain {
public static void main(String[] args) {
// @Configuration注启动spring容器方式,用注解配置上下文
ApplicationContext context = new AnnotationConfigApplicationContext(TestConfiguration.class);
// 如果加载spring-context.xml文件: ClassPathXmlApplicationContext("spring-context.xml")
}
}
1.2、@Configuration + @Bean,配置类启动容器并向spring容器中注入bean
待注入的 TestBean 类
public class TestBean {
private String username;
private String url;
private String password;
public void sayHello() {
System.out.println("TestBean sayHello...");
}
public void initMethod() {
System.out.println("TestBean 后初始化。。。");
}
public void destoryMethod() {
System.out.println("TestBean 预销毁。。。");
}
}
@Configuration配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
@Configuration
public class TestConfiguration {
public TestConfiguration() {
System.out.println("TestConfiguration容器启动初始化。。。");
}
// @Bean注解注册bean,同时可以指定初始化和销毁方法
// @Bean(name="testBean",initMethod="initMethod",destroyMethod="destoryMethod")
@Bean
@Scope("prototype") //原型模式即多例模式
public TestBean testBean() {
return new TestBean();
}
}
配置类启动容器并并注入testBean
public class TestMain {
public static void main(String[] args) {
//获取容器对象,执行完这一步后对象就已经在容器里面了
ApplicationContext context = new AnnotationConfigApplicationContext(TestConfiguration.class);
//获取bean
TestBean tb = (TestBean) context.getBean("testBean");
tb.sayHello();
}
}
控制台输出为:
TestConfiguration容器启动初始化。。。 说明配置类实例化了,并在容器中
TestBean sayHello...
上面的 @Scope(prototype) 说明是多例模式,对于多例模式的解释如下:
@Controller
@RequestMapping("/demo/lsh/ch5")
@Scope("prototype")
public class MultViewController {
private static int st = 0; //静态的
private int index = 0; //非静态
@RequestMapping("/test")
public String test() {
System.out.println(st++ + " | " + index++);
return "/lsh/ch5/test";
}
}
@Scope + @Component 指定bean的单例、多例模式,访问上面的contoller结果如下:
singleton 表示在spring容器中的单例,通过spring容器获得该bean时总是返回唯一的实例
prototype表示每次获得bean都会生成一个新的对象
单例模式 0 | 0 多例模式 0 | 0
1 | 1 1 | 0
2 | 2 2 | 0
3 | 3 3 | 0
4 | 4 4 | 0
我们来测试 @Bean + @Scope的效果
//配置类中注入bean
@Bean(initMethod = "initMethod", destroyMethod = "destoryMethod")
@Scope("prototype")
public First firstBean(){
return new First();
}
//Main 函数中,两次获取的bean不一样
ApplicationContext cpx = new AnnotationConfigApplicationContext(TestConfiguration.class);
First bean = cpx.getBean(First.class);
System.out.println(bean);
First bean1 = cpx.getBean(First.class);
System.out.println(bean1);
输出结果: 多例配置生效,后初始化方法执行 (存在于bean的生命周期)
测试类后初始化方法执行
com.kuang.dao.First@49070868
测试类后初始化方法执行
com.kuang.dao.First@6385cb26
1.3、@Configuration启动容器+@Component注册Bean
配置类启动容器,也可以不在配置类中用 @Bean注入bean,在配置类中直接开启注解扫描,使得所有的注解@Component生效。相当于@Configuration是 xml配置文件,@ComponentScan(“com.kuang.dao”)是 xml配置文件中的开启@Componen支持。
//待注入spring的类,需要开启 @Component支持
@Component
public class TestBean {
private String username;
public void sayHello() {
System.out.println("TestBean sayHello...");
}
}
配置类启动spring容器并 开启@Component支持
@Configuration
@ComponentScan(basePackages = "com.dxz.demo.configuration")
public class TestConfiguration {
public TestConfiguration() {
System.out.println("TestConfiguration容器启动初始化。。。");
}
}
这样标注@Component的类便会注入。相当于xml 配置中的
<context:component-scan base-package="com.kuang.dao"/>
1.4、使用 AnnotationConfigApplicationContext 注册多个配置类的方法
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext();
//注册多个配置类,相当于多个配置文件合并
ctx.register(AppContext.class)
ctx.register(AppContext1.class)
}
第二章:组合多个配置类
@configuration 搭配 @Import(配置类),多个配置类生效
@ImportResource("classpath:applicationContext.xml")、
搭配ImportResource配置类搭配配置文件一起使用,配置文件也生效。
@Import(TestConfiguration.class)
搭配import相当于另一个配置类也生效,注入另一个配置类,并注入其中声明的要注入的bean
待导入的 First 类
public class First {
private String name;
private Second second;
}
待导入的 Second 类
public class Second {
private String name;
private First a;
}
配置类1中导入 second
@Configuration
public class MyConfig {
@Bean(name = "second")
public Second getbean(){
return new Second();
}
}
配置类2中导入First,并@Import 配置类1
@Configuration
@Import(MyConfig.class)
public class TestConfiguration {
@Bean(name = "first")
@Scope("prototype")
public First firstBean(){
return new First();
}
测试发现 second、first、配置类1(还是基于@Component)都导入了:
public class Main {
public static void main(String[] args) {
ApplicationContext cpx = new AnnotationConfigApplicationContext(TestConfiguration.class);
First bean1 = (First) cpx.getBean("first");
Second bean2= (Second) cpx.getBean("second");
MyConfig config=cpx.getBean(MyConfig.class); //查看配置类1在不在容器中
System.out.println(bean1);
System.out.println(bean2);
System.out.println(config);
}
}
com.kuang.dao.First@646be2c3
com.kuang.dao.Second@797badd3
com.kuang.dao.MyConfig$$EnhancerBySpringCGLIB$$420c6c53@77be656f