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進行的。

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