Spring IOC 常用的注解


一、@Bean

1、配置類

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

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

2、測試類:

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")); } }

二、@ComponentScan 

在配置類上增加 @ComponentScan 注解,來進行包掃描;

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

1、basePackages 包掃描的路徑

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

2、excludeFilters,排除

(a)FilterType.ANNOTATION : 排除注解

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

@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:自定義規則去排除

@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; } }

3、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{ }

4、測試類

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(); } }

三、配置Bean的作用域對象

1、在不指定 @Scope 的情況下,所有的bean都是單實例的bean,而且是餓漢加載(容器啟動實例就創建好了)

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

2、指定@Scopeprototype 表示為多實例的,而且還是懶漢模式加載IOC容器啟動的時候,並不會創建對象,而是在第一次使用的時候才會創建)

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

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

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

四、@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 加載是有順序的, 越在前越更早的被加載;

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

1、通過 @CompentScan + @Controller @Service @Respository @compent

  適用場景: 針對我們自己寫的組件可以通過該方式來進行加載到容器中。

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

3、通過 @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 { }

運行結果

 4、通過實現 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名稱 之前加一個 & ;

六、Bean的初始化和銷毀方法

什么是bean的生命周期?

bean的創建----->初始化----->銷毀方法

由容器管理Bean的生命周期,我們可以通過自己指定bean的初始化方法和bean的銷毀方法?

1、方法一:使用 @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容器的管理;

2、通過 實現 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(); } }

運行結果:

3、通過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 的方法"); } }

運行結果:

 4、通過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; } }

運行結果

 七、通過@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; }

八、自動裝配

 1、@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自動注入策略。

3、@InJectJSR330規范)

 需要導入jar包依賴

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

@Inject 默認 By type 自動注入, 可以 通過@Qualifier 顯式指定 ByName 注入。

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

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

我們自己的組件,需要使用spring ioc的底層組件的時候比如 ApplicationContext等,我們可以通過實現XXXAware接口來實現 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM