1、包掃描+組件標注注解
使用到的注解如下,主要針對自己寫的類
- @Controller
- @Service
- @Repository
- @Component
- @ComponentScan
參考 spring注解開發:ComponentScan組件掃描
2、使用bean注解
主要使用場景:導入第三方包里面的組件,使用到的注解:
- @Bean
參考:spring注解開發:Configuration&Bean
3、使用@Import注解
- 使用方式:@Import(要導入到容器中的組件);容器中就會自動注冊這個組件
- bean的id默認是全類名
- 示例:@Import(value = {Person.class})
實戰
1、新建一個maven工程,添加如下依賴
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.5.RELEASE</version> </dependency>
2、新建一個實體 Person
package com.yefengyu.annotation.bean; public class Person { private String name; private Integer age; public Person() { } public Person(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
3、新建一個配置類(重點)
package com.yefengyu.annotation.config; import com.yefengyu.annotation.bean.Person; import org.springframework.context.annotation.*; @Configuration @Import(Person.class) public class MainConfig { }
4、測試代碼
public static void main(String[] args) { ApplicationContext ctx= new AnnotationConfigApplicationContext(MainConfig.class); String[] names = ctx.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } Person person1= (Person)ctx.getBean(Person.class); //bean的id默認是全類名 Person person2= (Person)ctx.getBean("com.yefengyu.annotation.bean.Person"); }
4、使用ImportSelector
ImportSelector和Import一起使用:首先編寫一個類實現ImportSelector接口MyImportSelector,然后將MyImportSelector添加到Import中,那么MyImportSelector自定義邏輯返回需要導入的組件就會被加入到容器中。
利用上面第三節的代碼,我們重新添加一個類,這個類什么都沒有,現在我們嘗試着使用ImportSelector方式將其注冊到容器中。
package com.yefengyu.annotation.bean; public class Car { }
1、編寫MyImportSelector實現ImportSelector接口,重寫selectImports方法,返回的數組中每個字符串就是要導入到容器的組件的全類名。
package com.yefengyu.annotation; import org.springframework.context.annotation.ImportSelector; import org.springframework.core.type.AnnotationMetadata; //自定義邏輯返回需要導入的組件 public class MyImportSelector implements ImportSelector { //返回值就是要導入到容器的組件的全類名 @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { return new String[]{"com.yefengyu.annotation.bean.Car"}; } }
2、修改MainConfig配置類,使用Import注解加入MyImportSelector類,注意下面紅色部分。
package com.yefengyu.annotation.config; import com.yefengyu.annotation.MyImportSelector; import com.yefengyu.annotation.bean.Person; import org.springframework.context.annotation.*; @Configuration @Import({Person.class, MyImportSelector.class}) public class MainConfig { }
3、測試,同樣使用上面的測試代碼,可以看出打印結果為:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
com.yefengyu.annotation.bean.Person
com.yefengyu.annotation.bean.Car
4、針對於public String[] selectImports(AnnotationMetadata annotationMetadata)方法中的參數AnnotationMetadata有很多信息可以幫助篩選要注冊的組件。
5、使用ImportBeanDefinitionRegistrar
和使用ImportSelector方式一樣,定義一個類實現ImportBeanDefinitionRegistrar接口,重寫其中的方法,手動注冊組件。
1、定一個類,作為要注冊的組件
package com.yefengyu.annotation.bean; public class Alarm { }
2、實現ImportBeanDefinitionRegistrar接口,手動注冊組件
package com.yefengyu.annotation; import com.yefengyu.annotation.bean.Alarm; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.type.AnnotationMetadata; public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) { beanDefinitionRegistry.registerBeanDefinition("alarm",new RootBeanDefinition(Alarm.class)); } }
beanDefinitionRegistry.registerBeanDefinition("alarm",new RootBeanDefinition(Alarm.class));
第一個參數是組件名稱。
第二個參數是要注冊的組件的類型的定義。
AnnotationMetadata 和上一節類似。BeanDefinitionRegistry 的功能很多:
3、修改MainConfig配置類,使用Import注解加入MyImportBeanDefinitionRegistrar類,注意下面紅色部分。
package com.yefengyu.annotation.config; import com.yefengyu.annotation.MyImportBeanDefinitionRegistrar; import com.yefengyu.annotation.MyImportSelector; import com.yefengyu.annotation.bean.Person; import org.springframework.context.annotation.*; @Configuration @Import({Person.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) public class MainConfig { }
4、測試,同樣使用上面的測試代碼,可以看出打印結果為:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
com.yefengyu.annotation.bean.Person
com.yefengyu.annotation.bean.Car
alarm
6、使用FactoryBean
1、首先創建一個待加入到容器的組件
package com.yefengyu.annotation.bean; public class Event { }
2、創建一個Spring定義的FactoryBean
package com.yefengyu.annotation; import com.yefengyu.annotation.bean.Event; import org.springframework.beans.factory.FactoryBean; //創建一個Spring定義的FactoryBean public class EventFactoryBean implements FactoryBean<Event> { //返回一個Event對象,這個對象會添加到容器中 @Override public Event getObject() throws Exception { return new Event(); } @Override public Class<?> getObjectType() { return Event.class; } //是單例? //true:這個bean是單實例,在容器中保存一份 //false:多實例,每次獲取都會創建一個新的bean; @Override public boolean isSingleton() { return true; } }
3、修改配置類,注意下面bean注解下面的代碼
package com.yefengyu.annotation.config; import com.yefengyu.annotation.EventFactoryBean; import com.yefengyu.annotation.MyImportBeanDefinitionRegistrar; import com.yefengyu.annotation.MyImportSelector; import com.yefengyu.annotation.bean.Person; import org.springframework.context.annotation.*; @Configuration @Import({Person.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) public class MainConfig { @Bean public EventFactoryBean eventFactoryBean() { return new EventFactoryBean(); } }
4、修改測試代碼如下:
package com.yefengyu.annotation; import com.yefengyu.annotation.bean.Person; import com.yefengyu.annotation.config.MainConfig; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Main { public static void main(String[] args) { ApplicationContext ctx= new AnnotationConfigApplicationContext(MainConfig.class); String[] names = ctx.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } //測試EventFactoryBean Object eventFactoryBean = ctx.getBean("eventFactoryBean"); System.out.println("bean 的類型為:" + eventFactoryBean.getClass()); Object factoryBean = ctx.getBean("&eventFactoryBean"); System.out.println("bean 的類型為:" + factoryBean.getClass()); } }
5、結果如下:
mainConfig com.yefengyu.annotation.bean.Person com.yefengyu.annotation.bean.Car eventFactoryBean alarm bean 的類型為:class com.yefengyu.annotation.bean.Event bean 的類型為:class com.yefengyu.annotation.EventFactoryBean
總結:
- 默認獲取到的是工廠bean調用getObject創建的對象
ctx.getBean("eventFactoryBean");
- 要獲取工廠Bean本身,我們需要給id前面加一個&
ctx.getBean("&eventFactoryBean");