一、配置類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")); } }
在配置類上增長 @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(); } }
一、在不指定 @Scope 的狀況下,全部的bean都是單實例的bean,並且是餓漢加載(容器啓動實例就建立好了)
@Bean public Person person() { return new Person(); }
二、指定@Scope爲 prototype 表示爲多實例的,並且仍是懶漢模式加載(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(); }
有二個組件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
適用場景: 針對咱們本身寫的組件能夠經過該方式來進行加載到容器中。
(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 { }
運行結果
實現 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 註解的 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(); } }
運行結果:
(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 的方法"); } }
運行結果:
(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; } }
運行結果
配置類
@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:
自動裝配首先時按照類型進行裝配,若在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 時, 那麼在裝配的時候就會拋出異常 ;
若咱們想不拋異常 ,咱們須要指定 required爲false的時候能夠了:@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自動注入策略。
須要導入jar包依賴
功能和支持 @Primary 功能 ,可是沒有 Require=false 的功能
@Inject 默認 By type 自動注入, 能夠 經過@Qualifier 顯式指定 ByName 注入。
@Autowired:Spring定義的;@Resource,@inject都是java規範。
咱們本身的組件,須要使用spring ioc的底層組件的時候, 好比 ApplicationContext等,咱們能夠經過實現XXXAware接口來實現