1.配置類
使用配置文件的形式代替配置類
2.包掃描注解
- 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.xsd"> <!--包掃描,只要標(biāo)注了@Controller乍炉,@Service,@Repository,@Component --> <!--<context:component-scan base-package="com.tarot"></context:component-scan>--> <bean id="person" class="com.tarot.bean.Person"> <property name="age" value="18"></property> <property name="name" value="tarot"></property> </bean> </beans>
- 配置類
- @Configuration:告訴spring這是一個(gè)配置類
- @ComponentScan(value = "url"):指定掃描包的路徑,ComponentScan在java1.8后為可重復(fù)拒接蹄胰,即可以多次使用定義掃描策略
- 配置屬性excludeFilters
excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class})}
- 該屬性指排除那些注解下的bean被掃描到苫拍。
其中:FilterType指使用哪種策略
- 該屬性指排除那些注解下的bean被掃描到苫拍。
- 配置屬性includeFilters
includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class})}
- 該屬性指包括那些注解下的bean被掃描到贝润。
- 該屬性與配置屬性u(píng)seDefaultFilters配合使用
- 配置屬性u(píng)seDefaultFilters
- useDefaultFilters是值是否使用默認(rèn)配置他匪,默認(rèn)值為true,當(dāng)指定掃描固定注解的bean掃描時(shí),要關(guān)閉默認(rèn)全部bean掃描。
3.指定掃描規(guī)則:Filter的掃描規(guī)則
- FilterType.ANNOTATION:默認(rèn)掃描規(guī)則栅干,按照注解的方式
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
- FilterType.ASSIGNABLE_TYPE:按照給定的類型
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {BookService.class})
- FilterType.ASPECTJ:使用ASPECTJ表達(dá)式
- FilterType.REGEX:使用正則表達(dá)式
- FilterType.CUSTOM:自定義規(guī)則
@ComponentScan.Filter(type = FilterType.CUSTOM,classes = {CustomTypeFilter.class})
- 使用自定義規(guī)則,需要編寫(xiě)自定義配置類捐祠,該類實(shí)現(xiàn)接口FilterType
/** * 自定義掃描規(guī)則 * 由于: * @ComponentScan(value = "com.tarot", * includeFilters = { * @ComponentScan.Filter(type = FilterType.CUSTOM,classes = {CustomTypeFilter.class}) * }, * useDefaultFilters = false * ) * value配置的路徑是:com.tarot碱鳞,所以所有的該路徑下的類都會(huì)去匹配該自定義包掃描規(guī)則 * @ClassPath: com.tarot.config.CustomTypeFilter * @Author: ZhaoHeJia * @Date: 2018/12/24 11:22 */ public class CustomTypeFilter implements TypeFilter { /** * * @param metadataReader 讀取到當(dāng)前正在掃描的類的信息 * @param metadataReaderFactory 讀取其他類信息 * @return 比對(duì)結(jié)果boolean * @throws IOException io異常 */ @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { //獲取當(dāng)前類注解的信息 AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); //獲取當(dāng)前正在掃描的類的信息 ClassMetadata classMetadata = metadataReader.getClassMetadata(); //獲取當(dāng)前類資源(類路徑) Resource resource = metadataReader.getResource(); String className = classMetadata.getClassName(); //自定義掃描規(guī)則 if (className.contains("service")){ return true; } return false; } }
4.配置Bean組件
- @Bean注解:往容器中注冊(cè)bean
@Bean public Person person(){ return new Person("22","zhj"); }
- 給容器注冊(cè)一個(gè)Bean,類型為返回值類型,id為方法名。即返回值Person相當(dāng)于xml文件的class屬性,方法名相當(dāng)于xml文件的id屬性
5.@Scope注解(Bean的作用域)
- @Scope注解:bean的作用域,默認(rèn)為singleton
- 取值:
- SINGLETON:?jiǎn)螌?shí)例踱蛀,當(dāng)ioc容器啟動(dòng)時(shí)會(huì)創(chuàng)建該方法的實(shí)例窿给,加入到ioc容器中,之后直接調(diào)用
當(dāng)一個(gè)bean的 作用域設(shè)置為singleton, 那么Spring IOC容器中只會(huì)存在一個(gè)共享的bean實(shí)例率拒,并且所有對(duì)bean的請(qǐng)求崩泡,只要id與該bean定義相匹配,則只會(huì)返回bean的同一實(shí)例猬膨。換言之角撞,當(dāng)把 一個(gè)bean定義設(shè)置為singleton作用域時(shí),Spring IOC容器只會(huì)創(chuàng)建該bean定義的唯一實(shí)例勃痴。這個(gè)單一實(shí)例會(huì)被存儲(chǔ)到單例緩存(singleton cache)中谒所,并且所有針對(duì)該bean的后續(xù)請(qǐng)求和引用都 將返回被緩存的對(duì)象實(shí)例,這里要注意的是singleton作用域和GOF設(shè)計(jì)模式中的單例是完全不同的沛申,單例設(shè)計(jì)模式表示一個(gè)ClassLoader中 只有一個(gè)class存在劣领,而這里的singleton則表示一個(gè)容器對(duì)應(yīng)一個(gè)bean,也就是說(shuō)當(dāng)一個(gè)bean被標(biāo)識(shí)為singleton時(shí) 候污它,spring的IOC容器中只會(huì)存在一個(gè)該bean剖踊。
- PROTOTYPE:多實(shí)例,ioc實(shí)例啟動(dòng)并不創(chuàng)建實(shí)例衫贬,每次獲取該實(shí)例對(duì)象時(shí)才會(huì)ioc才會(huì)創(chuàng)建該實(shí)例
prototype作用域部署的bean德澈,每一次請(qǐng)求(將其注入到另一個(gè)bean中,或者以程序的方式調(diào)用容器的 getBean()方法)都會(huì)產(chǎn)生一個(gè)新的bean實(shí)例固惯,相當(dāng)與一個(gè)new的操作梆造,對(duì)于prototype作用域的bean,有一點(diǎn)非常重要葬毫,那就是Spring不能對(duì)一個(gè)prototype bean的整個(gè)生命周期負(fù)責(zé)镇辉,容器在初始化、配置贴捡、裝飾或者是裝配完一個(gè)prototype實(shí)例后忽肛,將它交給客戶端,隨后就對(duì)該prototype實(shí)例不聞不問(wèn)了烂斋。不管何種作用域屹逛,容器都會(huì)調(diào)用所有對(duì)象的初始化生命周期回調(diào)方法础废,而對(duì)prototype而言,任何配置好的析構(gòu)生命周期回調(diào)方法都將不會(huì)被調(diào)用
- REQUEST:同一次請(qǐng)求創(chuàng)建一個(gè)實(shí)例罕模,web環(huán)境
request表示該針對(duì)每一次HTTP請(qǐng)求都會(huì)產(chǎn)生一個(gè)新的bean评腺,同時(shí)該bean僅在當(dāng)前HTTP request內(nèi)有效
- SESSION:同一個(gè)session創(chuàng)建一個(gè)實(shí)例,web環(huán)境
session作用域表示該針對(duì)每一次HTTP請(qǐng)求都會(huì)產(chǎn)生一個(gè)新的bean淑掌,同時(shí)該bean僅在當(dāng)前HTTP session內(nèi)有效
- ps:spring中scope作用域
6.@Lazy注解(懶加載)
- 在單實(shí)例的情況下
- 在容器啟動(dòng)的時(shí)候并不創(chuàng)建對(duì)象蒿讥,而是在第一次使用(獲取)Bean對(duì)象時(shí)創(chuàng)建。
7.@Conditional注解(在一定條件下創(chuàng)建bean)
- 可以注解在配置類和bean上
- 只在一定條件下該bean生效
- @Conditional的配置屬性value可以是一個(gè)類抛腕,該類邏輯判斷由實(shí)現(xiàn)Condition接口完成芋绸。
- 當(dāng)不同操作系統(tǒng)注入不同的bean
@Configuration public class MainConfig2 { /** * 在windows操作系統(tǒng)下該bean注冊(cè)生效 * @return bean類型 */ @Conditional(value = WindowCondition.class) @Bean("window") public Person person01(){ return new Person("1111","win"); } /*** * 在linux操作系統(tǒng)下該bean生效 * @return bean類型 */ @Conditional(value = LinuxCondition.class) @Bean("linux") public Person person02(){ return new Person("0000","lnx"); } }
- 編寫(xiě)Condition注解的條件
public class WindowCondition implements Condition { /** * * @param context 判斷條件的上下文對(duì)象 * @param metadata 當(dāng)前標(biāo)注了condition的注釋信息 * @return */ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { //獲取ioc使用的beanFactory ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); //獲取類加載器 ClassLoader classLoader = context.getClassLoader(); //獲取當(dāng)前環(huán)境信息 Environment environment = context.getEnvironment(); //獲取bean注冊(cè)的注冊(cè)類 BeanDefinitionRegistry registry = context.getRegistry(); //獲取當(dāng)前操作系統(tǒng)類型信息 String property = environment.getProperty("os.name"); //忽略大小寫(xiě) if(property.toLowerCase().contains("window")){ return true; } return false; } }
public class LinuxCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Environment environment = context.getEnvironment(); String property = environment.getProperty("os.name"); if (property.toLowerCase().contains("linux")){ return true; } return false; } }
- 測(cè)試
public class IOCTest { @Test @SuppressWarnings("resource") public void test03(){ //獲取使用注解配置的bean AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); //獲取當(dāng)前的運(yùn)行環(huán)境 ConfigurableEnvironment environment = applicationContext.getEnvironment(); String property = environment.getProperty("os.name"); System.out.println("當(dāng)前操作系統(tǒng):"+property); //根據(jù)類型獲取ioc注冊(cè)的bean,由于注冊(cè)的name="linux"的bean生效為linux系統(tǒng)兽埃,故此時(shí)并沒(méi)有注冊(cè) String[] names = applicationContext.getBeanNamesForType(Person.class); for (String name:names){ System.out.println("注冊(cè)bean:"+name); } //以map形式獲取bean信息 Map<String, Person> beansOfType = applicationContext.getBeansOfType(Person.class); System.out.println(beansOfType); } }
-
測(cè)試結(jié)果
測(cè)試window操作系統(tǒng)結(jié)果 -
修改運(yùn)行配置
修改當(dāng)前操作系統(tǒng)名為linux -
測(cè)試結(jié)果
測(cè)試inux下結(jié)果
8.@import注解
- 給容器中注入bean的方式
- 包掃描+組件標(biāo)注注解(@Controller/@Service/@Repository/@Component)
- 使用Bean(導(dǎo)入第三方包里面的組件)
- 使用@Import方式(快速導(dǎo)入)
- 使用Spring提供的FactoryBean(工廠Bean)
- 導(dǎo)入組件侥钳,id默認(rèn)為全類名
@Import(value = {bean1.class,bean2.class})
- 實(shí)現(xiàn)ImportSelector接口方法導(dǎo)入多個(gè):返回需要導(dǎo)入的租金按的全類名數(shù)組
- 導(dǎo)入組件
@Import(value = {Black.class,CustomImportSelector.class}) public class MainConfig2 {}
- 實(shí)現(xiàn)ImportSelector接口方法
public class CustomImportSelector implements ImportSelector { /** * * @param importingClassMetadata:當(dāng)前標(biāo)注@import注解的類的所有注解信息 * @return 導(dǎo)入到容器的組件全類名 */ @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { //返回值不能為null,可返回空數(shù)組new String[]{} return new String[]{"com.tarot.bean.Red","com.tarot.bean.Yellow"}; } }
- 實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口,使用手工注冊(cè)的方式注冊(cè)
- 導(dǎo)入組件
@Import(value = {Black.class,CustomImportSelector.class,CustomImportBeanDefinitionRegistrar.class}) public class MainConfig2 {}
- 實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口方法
public class CustomImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * * @param importingClassMetadata:當(dāng)前標(biāo)注@import注解的類的所有注解信息 * @param registry bean注冊(cè)類 * 把所有需要添加到容器中的bean,通過(guò)BeanDefinitionRegistry.registerBeanDefinition方法手工注冊(cè) */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { //判斷容器中是否有該bean boolean black = registry.containsBeanDefinition("com.tarot.bean.Black"); if(black){ //指定Bean定義信息:(Bean的類型...) RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Blue.class); //指定bean名 registry.registerBeanDefinition("Blue",rootBeanDefinition); } } }
- 導(dǎo)入組件
9.使用Spring提供的FactoryBean(工廠Bean)
- 實(shí)現(xiàn)FactoryBean<T>接口适袜,其中T為Bean,默認(rèn)實(shí)現(xiàn)的類的類型為Bean(T)的類型柄错,由工廠
整合其他框架,spring內(nèi)部廣泛使用 - FactoryBean是一個(gè)接口苦酱,當(dāng)在IOC容器中的Bean實(shí)現(xiàn)了FactoryBean后售貌,通過(guò)getBean(String BeanName)獲取到的Bean對(duì)象并不是FactoryBean的實(shí)現(xiàn)類對(duì)象,而是這個(gè)實(shí)現(xiàn)類中的getObject()方法返回的對(duì)象疫萤。要想獲取FactoryBean的實(shí)現(xiàn)類颂跨,就要getBean(&BeanName),在BeanName之前加上&
- 一般情況下扯饶,Spring通過(guò)反射機(jī)制利用<bean>的class屬性指定實(shí)現(xiàn)類實(shí)例化Bean恒削,在某些情況下,實(shí)例化Bean過(guò)程比較復(fù)雜尾序,如果按照傳統(tǒng)的方式钓丰,則需要在<bean>中提供大量的配置信息。配置方式的靈活性是受限的每币,這時(shí)采用編碼的方式可能會(huì)得到一個(gè)簡(jiǎn)單的方案携丁。Spring為此提供了一個(gè)org.springframework.bean.factory.FactoryBean的工廠類接口,用戶可以通過(guò)實(shí)現(xiàn)該接口定制實(shí)例化Bean的邏輯兰怠。FactoryBean接口對(duì)于Spring框架來(lái)說(shuō)占用重要的地位梦鉴,Spring自身就提供了70多個(gè)FactoryBean的實(shí)現(xiàn)。
- 編寫(xiě)一個(gè)FactoryBean的實(shí)現(xiàn)類揭保,實(shí)現(xiàn)T為普通Bean(Black).注入到容器中肥橙。
- 編寫(xiě)B(tài)lack的實(shí)現(xiàn)類
public class CustomColorFactoryBean implements FactoryBean<Black> { /** * * @return 返回Black對(duì)象 * @throws Exception */ @Override public Black getObject() throws Exception { System.out.println("into factory bean..."); return new Black(); } /** * * @return 對(duì)象的類型 */ @Override public Class<?> getObjectType() { return Black.class; } /** * 判斷是否是單例 * @return true:單實(shí)例,容器保存一份秸侣;false:每次獲取都創(chuàng)建一個(gè)新的Bean */ @Override public boolean isSingleton() { return true; } }
- 注入CustomColorFactoryBean,獲取該Bean類型默認(rèn)為Black
@Bean public CustomColorFactoryBean customColorFactoryBean(){ return new CustomColorFactoryBean(); }
ps:BeanFactory 簡(jiǎn)介以及它 和FactoryBean的區(qū)別
10.Bean的生命周期
- Bean的生命周期:Bean創(chuàng)建---初始化---銷毀 過(guò)程
- ioc容器管理bean的生命周期存筏,我們可以自定義初始化和銷毀方法:即容器在bean進(jìn)行到當(dāng)前生命周期時(shí)調(diào)用我們自定義的初始化和銷毀方法娜庇。
- 構(gòu)造(創(chuàng)建對(duì)象)
- 單實(shí)例:在容器啟動(dòng)的時(shí)候創(chuàng)建對(duì)象
- 多實(shí)例:在每次獲取的時(shí)候創(chuàng)建對(duì)象,并初始化
- 初始化:?jiǎn)螌?shí)例方篮,對(duì)象創(chuàng)建完名秀,賦值后,調(diào)用初始化方法
- 銷毀:
- 單實(shí)例:當(dāng)ioc容器關(guān)閉時(shí)藕溅,bean銷毀
- 多實(shí)例:容器不會(huì)管理bean匕得,容器不會(huì)調(diào)用銷毀方法。
- 調(diào)用自定義初始化和銷毀方法
- 使用注解屬性的方式指定哪個(gè)方法為該初始化和銷毀方法巾表。
@Bean(initMethod = "init",destroyMethod = "destroy")
- 通過(guò)Bean實(shí)現(xiàn)接口InitializingBean(定義初始化)
- 通過(guò)Bean實(shí)現(xiàn)接口DisposableBean(銷毀)
public class BeanLiftCycle2 implements InitializingBean, DisposableBean { public BeanLiftCycle2(){ System.out.println("bean2 constructor..."); } @Override public void afterPropertiesSet() throws Exception { System.out.println("bean2 init..."); } @Override public void destroy() throws Exception { System.out.println("bean2 destroy..."); } }
- 使用JSR250規(guī)范注解,作用到bean的方法上
@PostConstruct:在bean創(chuàng)建完成后并屬性賦值汁掠,執(zhí)行初始化。
@PreDestroy:在容器銷毀bean前通知清理工作集币。 - 使用bean的后置處理器:實(shí)現(xiàn)BeanPostProcessor接口
其中方法:- postProcessBeforeInitialization:在初始化工作前調(diào)用
- postProcessAfterInitialization:在初始化工作后調(diào)用
@Component public class CustomBeanPostProcessor implements BeanPostProcessor{ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("bean后置處理器--初始化前調(diào)用方法"+beanName+"--->"+bean); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("bean后置處理器--初始化后調(diào)用方法"+beanName+"--->"+bean); return bean; } }