Spring中@Configuration的使用

        从Spring3.0,@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被ConfigurationClassPostProcessor类进行扫描,并用于构建bean定义,初始化Spring容器。

       我们先来看一下@Configuration注解的源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {

	@AliasFor(annotation = Component.class)
	String value() default "";
}

      可以看到@Configuration内部又有一个@Component注解,所以,其作用和@Component注解一样,都能将一个标有@Configuration的注解类,通过Spring包扫描和解析,最终形成Spring的bean。不过Spring在内部对于加了@Configuration注解的配和加了@Component注解的类,处理起来是由差别的,如果有同学想要探究Spring对于@Configuration注解的类和其他@Component注解的类的不同,可以查看:Spring中@Configuration源码深度解析(一)Spring中@Configuration源码深度解析(二),深入学习@Configuration注解。

      Spring从3.0开始引入@Configuration是为了替代XML形式的配置文件,当你在做ssm项目的时候,使用的应该是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" 
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context-4.0.xsd default-lazy-init="false">
	<context:component-scan base-package="com.luban.factory" />

    <bean id="school" class="com.luban.factory.School" >
	    <property name = "student" ref ="student"></property>
	</bean>
	<bean id="student" class="com.luban.factory.Student"/>
</beans>

      使用@Configuration来替换xml配置类如下:

@Configuration
@ComponentScan("com.luban.factory") //对应xml里面的context:component-scan标签
public class Config {
	@Bean  //对应xml里面的Bean标签
	public School school(){
		School school = new School();
		//给school对象设置属性
		school.setStudent(student());
		return school;
	}

	@Bean
	public Student student(){
		return new Student();
	}
}

       他们所完成的事情是相同的,在方法上使用@Bean就相当于xml里面的bean标签,@ComponentScan用来指定需要扫描的包的全路径,会把路径下在类上面标注了@Component、@Service、@Configuration等注入到容器中。

       由于是作为配置类来使用,有的人该说了,既然@Configuration底层就是使用@Component注解,那么能不能不用了@Configuration了,直接用@Component注解,那下面我们来实验一下,把@Configuration换成@Component试一下:

@Component  //本次使用的是@Component 
@ComponentScan("com.luban.factory")
public class Config {
	@Bean
	public School school(){
		School school = new School();
		//给school对象设置属性
		school.setStudent(student());
		return school;
	}
	@Bean
	public Student student(){
		return new Student();
	}
}

public class Test01 {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
		System.out.println(context.getBean("school"));
		System.out.println(context.getBean("student"));
	}
}

//打印结果:
//com.luban.factory.School@41a4555e
//com.luban.factory.Student@3830f1c0
//com.luban.factory.Student@39ed3c8d

     并且该配置类能够注入到容器里面,并且也可以完成对@Bean的解析,并把@Bean标注的方法变成Bean注入到容器中。

     我们再将@Component换成@Configuration试一下:

@Configuration//本次使用的是@Configuration
@ComponentScan("com.luban.factory")
public class Config {
	@Bean
	public School school(){
		School school = new School();
		//给school对象设置属性
		school.setStudent(student());
		return school;
	}
	@Bean
	public Student student(){
		return new Student();
	}
}

public class Test01 {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
		System.out.println(context.getBean("school"));
		System.out.println(context.getBean("student"));
	}
}
//其打印结果
//com.luban.factory.School@6debcae2
//com.luban.factory.Student@5ba23b66
//com.luban.factory.Student@5ba23b66

       发现@Component和@Configuration没什么区别啊,都能完成对Spring中Bean的管理,不过呢,你仔细看打印结果,多看两遍后你会发现,使用@Configuration注解之后,student对象是同一个,而使用@Component注解的话,student对象不是同一个,为什么加了@Configuration注解之后,student对象就是同一个呢,就只是改了一个注解而已,这是你可以知道了,肯定是加了@Configuration注解之后,Spring对其做了不同的处理,其实就是这样的,能够完成这样的工作,肯定是使用了代理,又因为这个配置类没有接口,所以可以断定,加了@Configuration之后,会使用cglib对其进行增强,然后进行方法拦截。如果想深入了解Spring对@Configuration的处理过程,请查看Spring中@Configuration源码深度解析(一)Spring中@Configuration源码深度解析(二),深入学习@Configuration注解。

     关于@Configuration有了一定的了解,就要看一下@Bean注解的使用,基本上@Configuration注解类里面都是定义@Bean注解的方法,以这样的方式往容器中注入bean,

     我们来查看一下@Bean的源码:

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
        //指定bean的名称
	@AliasFor("name")
	String[] value() default {};

	@AliasFor("value")
	String[] name() default {};
        //属性的注入模型
	Autowire autowire() default Autowire.NO;
        //指定init方法
	String initMethod() default "";
        //指定destroy方法
	String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
}

    所以使用@Bean注解可以写成这样的格式:

@Bean(name = "sch",initMethod = "init" ,destroyMethod = "destroy")
public School school(){
	School school = new School();
	//给school对象设置属性
	school.setStudent(student());
	return school;
}
public class School {
	private Student student;
	public Student getStudent() {
		return student;
	}
	public void setStudent(Student student) {
		this.student = student;
	}
	public void init(){
		System.out.println("执行init方法");
	}
	public void destroy(){
		System.out.println("执行destroy方法");
	}
}
public class Test01 {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
		School school = (School) context.getBean("sch"); //此时取的是sch
		System.out.println(school);
		context.destroy();
	}
}

//其打印结果:
//执行init方法
//com.luban.factory.School@41a4555e
//执行destroy方法

        注意这里指定initMethod和destroyMethod的方法,需要是School对象的方法,不能是其他对象的。

关于@Configuration的总结:

     1.@Configuration标注的类会被cglib代理,从而进行增强

     2.@Configuration标注的类不能使用final关键字修饰(cglib是使用继承增强需要代理的类的)

     3.@Configuration标注的类在@Bean方法内部调用其他标有@Bean的方法时,会被拦截,然后直接直接从容器中进行获取,不用再次创建(就因为有这一点,所以配置类要是有@Configuration,使用其他的可能会带来不必要的错误)

     4.@Configuration标注的类会被标注为full类型的,用来区分@Component、@Service等注解,增强的时候就是根据是不是full进行的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章