Spring IOC 經常使用的註解

1、@Bean

一、配置類java

@Configuration public class MainConfig { @Bean public Person person(){ return new Person(); } }

注意:經過@Bean的形式是使用的話, bean的默認名稱是方法名,可使用 @Bean(value="bean的名稱") 去指定bean的名稱;spring

二、測試類:session

public class MainClass { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class); //Arrays.stream(ctx.getBeanDefinitionNames()).forEach(System.out::println);
        System.out.println(ctx.getBean("person")); } }

2、@ComponentScan 

在配置類上增長 @ComponentScan 註解,來進行包掃描;ide

@ComponentScan 註解 配合 @Controller、@Service、@Component、@Reposity 使用,將類註冊到IOC容器中;post

一、basePackages 包掃描的路徑測試

@Configuration //掃描com.yufeng.componentscan包下的全部
@ComponentScan(basePackages = {"com.yufeng.componentscan"}) public class MainConfig { }

二、excludeFilters,排除ui

(a)FilterType.ANNOTATION : 排除註解spa

(b)FilterType.ASSIGNABLE_TYPE:排除具體的類prototype

@Configuration //掃描com.yufeng.componentscan包下的全部, 排除有@Controller註解的類, 排除類TuService
@ComponentScan(basePackages = {"com.yufeng.componentscan"}, excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Controller.class}), @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {TuService.class})}) public class MainConfig { }

(c)FilterType.CUSTOM:自定義規則去排除3d

@Configuration //掃描com.yufeng.componentscan包下的全部, 按照自定義規則排除
@ComponentScan(basePackages = {"com.yufeng.componentscan"}, excludeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, value = {MyTypeFilter.class})}) public class MainConfig { }

自定義的規則(實現 TypeFilter 接口):類名中包含dao的須要排除

public class MyTypeFilter implements TypeFilter { @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { //獲取當前類的註解源信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); //獲取當前類的class的源信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata(); //獲取當前類的資源信息
        Resource resource = metadataReader.getResource(); System.out.println("類的路徑:"+classMetadata.getClassName()); if(classMetadata.getClassName().contains("dao")) { return true;  //返回true, 則須要去過濾掉, 因此類名中包含dao的類不會被加載到IOC容器中
 } return false; } }

三、includeFilters  包含,在包掃描的當前路徑下只加載 includeFilters  包含的,其餘的不加載;

注意:須要把 useDefaultFilter 屬性設置爲 false (true表示全表掃描) 

@Configuration //--------------包含 includeFilters -------------
@ComponentScan(basePackages = {"com.yufeng.componentscan"}, includeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {Person.class})}, useDefaultFilters = false) public class MainConfig{ }

四、測試類

public class MainClass { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class); Arrays.stream(ctx.getBeanDefinitionNames()) .forEach(name -> System.out.println("bean的自定義: " + name)); ctx.close(); } }

 

3、配置Bean的做用域對象

一、在不指定 @Scope 的狀況下,全部的bean都是單實例的bean,並且是餓漢加載(容器啓動實例就建立好了)

 

@Bean public Person person() { return new Person(); }

二、指定@Scopeprototype 表示爲多實例的,並且仍是懶漢模式加載IOC容器啓動的時候,並不會建立對象,而是在第一次使用的時候纔會建立)

@Bean @Scope(value = "prototype") public Person person() {   return new Person(); }

三、@Scope指定的做用域方法取值
  (a)singleton 單實例的(默認)
  (b)prototype 多實例的
  (c)request 同一次請求
  (d)session 同一個會話級別
單實例的Bean要實現懶加載,可使用 @Lazy 註解 (主要針對單實例的bean 容器啓動的時候,不建立對象,在第一次使用的時候纔會建立該對象)

@Bean @Lazy public Person person() { return new Person(); } 

4、@Conditional 進行條件判斷

有二個組件TulingAspect 和 TulingLog ,個人TulingLog組件是依賴於TulingAspect的組件
自定義加載條件的類 TulingCondition,該類 實現Condition接口

 

public class MyCondition implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory(); //判斷容器中是否有tulingAspect的組件
        if(beanFactory.containsBean("tulingAspect")) { return true; } return false; } }

 

配置類的配置

@Configuration public class ConditionConfig { //當前容器中有tulingAspect的組件,那麼tulingLog纔會被實例化
 @Bean @Conditional(value = MyCondition.class) public TulingLog tulingLog() { return new TulingLog(); } @Bean public TulingAspect tulingAspect() { return new TulingAspect(); } }

運行結果以下:

 

 

注意:@Configuration 配置類中的 Bean 加載是有順序的, 越在前越更早的被加載;


5、IOC 容器中添加組件的方式

一、經過 @CompentScan + @Controller @Service @Respository @compent

  適用場景: 針對咱們本身寫的組件能夠經過該方式來進行加載到容器中。

二、經過 @Bean 的方式來導入組件(適用於導入第三方組件的類)

三、經過 @Import 來導入組件 (導入Bean的id爲全類名路徑

(1)方式一: @Import(value = {Person.class,  Car.class})

配置類:

@Configuration @Import(value = {Person.class, Car.class}) public class MainConfig { }

 

運行結果:

 

 

 (2)方式二:按照全類名導入,經過@Import 的 ImportSeletor 類 (導入Bean的id爲全類名路徑)

實現  ImportSelector 接口,按照類的全路徑名導入

 

public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { return new String[]{"com.yufeng.importanno.component.Dog"}; } }

 

配置類:

 

@Configuration //@Import(value = {Person.class, Car.class})
@Import(value = {Fish.class, MyImportSelector.class}) public class MainConfig { }

 

運行結果

 

 

 (3)方式三: 經過 @Import 導入  ImportBeanDefinitionRegister 的實現類 (能夠指定bean的名稱)

 

實現  ImportBeanDefinitionRegister  接口

 

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) { //建立一個bean定義對象
        RootBeanDefinition beanDefinition = new RootBeanDefinition(Car.class); //把bean定義對象導入到容器中
        beanDefinitionRegistry.registerBeanDefinition("car", beanDefinition); } }

 

配置類

@Configuration //@Import(value = {Person.class, Car.class}) //@Import(value = {Fish.class, MyImportSelector.class})
@Import(value = {MyImportSelector.class, MyImportBeanDefinitionRegistrar.class, Person.class}) public class MainConfig { }

運行結果

 

 

 四、經過實現 FacotryBean 接口來實現註冊組件

 實現  FactoryBean 接口,重寫 getObject、getObjectType、isSingleton 方法;

public class CarFactoryBean implements FactoryBean { //返回bean的對象
 @Override public Car getObject() throws Exception { return new Car(); } //返回bean的類型
 @Override public Class<?> getObjectType() { return Car.class; } //是否爲單利
 @Override public boolean isSingleton() { return true; } }

配置類:

@Configuration public class MainConfig { @Bean public CarFactoryBean carFactoryBean() { return new CarFactoryBean(); } }

測試類:

public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class); Arrays.stream(ctx.getBeanDefinitionNames()) .forEach(name -> System.out.println("bean名字: " + name));
System.out.println(
"--------------"); Object bean = ctx.getBean("carFactoryBean"); System.out.println(bean.getClass().getName()); System.out.println("--------------"); Object bean2 = ctx.getBean("&carFactoryBean"); System.out.println(bean2.getClass().getName()); } }

運行結果

 

 

 結論:

(1)實現 FactoryBean 接口的類,註冊到IOC容器中,使用 bean名稱 獲取到的是Bean的 getObject 方法返回的對象;

(2)實現 FactoryBean 接口的類,註冊到IOC容器中,要想獲取到Bean自己,則在 bean名稱 以前加一個 & ;

6、Bean的初始化和銷燬方法

什麼是bean的生命週期?

bean的建立----->初始化----->銷燬方法

由容器管理Bean的生命週期,咱們能夠經過本身指定bean的初始化方法和bean的銷燬方法?

一、方法一:使用 @Bean 註解的 initMethod  和 destroyMethod 

(1)組件:

public class Car { public Car() { System.out.println("-------Car構造方法------"); } public void init(){ System.out.println("-------Car的 init() 方法------"); } public void destroy() { System.out.println("-------Car的 destroy() 方法------"); } }

(2)配置類,使用 @Bean 註解的 initMethod  和 destroyMethod

@Configuration public class MainConfig { @Bean(initMethod = "init", destroyMethod = "destroy") public Car car() { return new Car(); } }

(3)測試類

public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class); /*Arrays.stream(ctx.getBeanDefinitionNames()) .forEach(name -> System.out.println("bean名字: " + name));*/ ctx.close(); } }

運行結果:

 

注意:

(1)針對單實例bean的話,容器啓動的時候,bean的對象就建立了,並且容器銷燬的時候,也會調用Bean的銷燬方法;

(2)針對多實例bean的話,容器啓動的時候,bean是不會被建立的而是在獲取bean的時候被建立,並且bean的銷燬不受 IOC容器的管理;

二、經過 實現 InitializingBean 和 DisposableBean 接口,並重寫bean的初始化以及銷燬方法 ;

(1)組件實現 InitializingBean 和 DisposableBean 接口

@Component public class Person implements InitializingBean, DisposableBean { public Person() { System.out.println("--Person的構造方法--"); } @Override public void destroy() throws Exception { System.out.println("Person DisposableBean的destroy()方法"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("Person InitializingBean的 afterPropertiesSet方法"); } }

(2)配置類

@Configuration @ComponentScan(basePackages = "com.yufeng.beanlifecyle") public class MainConfig { @Bean(initMethod = "init", destroyMethod = "destroy") public Car car() { return new Car(); } }

運行結果:

 

 

 

三、經過JSR250規範 提供的註解@PostConstruct @ProDestory標註的方法

 

 (1)組件

@Component public class Book { public Book() { System.out.println("Book的構造方法"); }  @PostConstruct public void myInit(){ System.out.println("Book 的標註 @PostConstruct 的方法"); }   @PreDestroy public void myDestroy() { System.out.println("Book 的標註 @PreDestroy 的方法"); } }

運行結果:

 

 四、經過Spring的 BeanPostProcessor bean的後置處理器會攔截全部bean建立過程

(1)postProcessBeforeInitialization  init 方法以前調用

(2)postProcessAfterInitialization 在 init 方法以後調用

實現 BeanPostProcessor  接口

@Component public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("MyBeanPostProcessor...postProcessBeforeInitialization:"+beanName); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("MyBeanPostProcessor...postProcessAfterInitialization:"+beanName); return bean; } }

運行結果

 

 

 

 7、經過@Value +@PropertySource來給組件賦值

配置類

@Configuration @PropertySource(value = {"classpath:person.properties"}) //指定外部文件的位置
public class MainConfig { @Bean public Person person() { return new Person(); } }

組件

public class Person { //經過普通的方式
    @Value("司馬") private String firstName; //spel方式來賦值
    @Value("#{28-8}") private Integer age; //經過讀取外部配置文件的值
    @Value("${person.lastName}") private String lastName; }

 

8、自動裝配

 一、@AutoWired的使用

 (1)@AutoWired:

  自動裝配首先時按照類型進行裝配,若在IOC容器中發現了多個相同類型的組件,那麼就按照 屬性名稱 來進行裝配 ;

好比,容器中有二個 TulingDao 類型的組件 一個叫 tulingDao 一個叫 tulingDao2,

那麼咱們經過@AutoWired 來修飾的屬性名稱爲tulingDao 那麼那就加載容器的tulingDao組件,若屬性名稱爲 tulignDao2 那麼他就加載的時tulingDao2組件。

 (2)@AutoWired 和 @Qualifier(value)  配合使用

假設咱們須要指定特定的組件來進行裝配,咱們能夠經過使用 @Qualifier("tulingDao") 來指定裝配的組件或者在配置類上的 @Bean 加上 @Primary 註解

@Autowired @Qualifier("tulingDao") private TulingDao tulingDao2; 

注意:若容器中既沒有 tulingDao也沒有 tulingDao2 時,  那麼在裝配的時候就會拋出異常 ;

           若咱們想不拋異常 ,咱們須要指定 requiredfalse的時候能夠了:@Autowired(required = false)

 

2@Resource 使用 (JSR250規範)

  功能和 @AutoWired 的功能差很少同樣,可是 不支持@Primary @Qualifier的支持 ,由J2EE提供,須要導入包javax.annotation.Resource。

@Resource 默認按照ByName自動注入@Resource有兩個重要的屬性:name和type而Spring將@Resource註解的name屬性解析爲bean

的名字,而type屬性則解析爲bean的類型。因此,

若是使用name屬性,則使用byName的自動注入策略;

若是使用type屬性時則使用byType自動注入策略。

若是既不指定 name也不制定type屬性,這時將經過反射機制使用byName自動注入策略。

三、@InJectJSR330規範)

 須要導入jar包依賴

功能和支持 @Primary 功能 ,可是沒有 Require=false 的功能

@Inject 默認 By type 自動注入, 能夠 經過@Qualifier 顯式指定 ByName 注入。

 @Autowired:Spring定義的;@Resource,@inject都是java規範。

9、經過實現XXXAware接口的實現,來從IOC容器中獲取 Bean

咱們本身的組件,須要使用spring ioc的底層組件的時候好比 ApplicationContext等,咱們能夠經過實現XXXAware接口來實現 

相關文章
相關標籤/搜索