spring学习之 @Configuration的使用及其原理

@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
  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值