Spring體系結構
-
SpringCore
框架最基礎的部分,提供IOC和依賴注入特性
-
SpringContext
Spring上下文容器,它是BeanFactory功能加強的一個子接口
-
SpringWeb
提供Web應用開發的支持
-
SpringMVC
針對Web應用中MVC思想的實現
-
SpringDao
對JDBC抽象層,簡化了JDBC編碼,同時,編碼更具有健壯性
-
SpringORM
用於流行的ORM框架的整合,比如:Spring + Hibernate、Spring + MyBatis、Spring + JDO的整合等等。
-
SpringAop
面向切面編程,它提供了與AOP聯盟兼容的編程實現
核心類
-
ApplicationContext 這是spring容器的上下文對象,所有注入的bean都會在容器中,初始化上下文後,就可以通過上下文對象獲取容器中的類。
-
BeanFactory
BeanFactory是接口,提供了OC容器最基本的形式,給具體的IOC容器的實現提供了規範。
BeanFacotry是spring中比較原始的Factory。如XMLBeanFactory就是一種典型的BeanFactory。原始的BeanFactory無法支持spring的許多插件,如AOP功能、Web應用等。
ApplicationContext接口,它由BeanFactory接口派生而來,ApplicationContext包含BeanFactory的所有功能,通常建議比BeanFactory優先
-
FactoryBean
爲IOC容器中Bean的實現提供了更加靈活的方式,FactoryBean在IOC容器的基礎上給Bean的實現加上了一個簡單工廠模式和裝飾模式(如果想了解裝飾模式參考:修飾者模式(裝飾者模式,Decoration) 我們可以在getObject()方法中靈活配置。其實在Spring源碼中有很多FactoryBean的實現類.
-
BeanPostProcessor
給容器中註冊組件的方式
- @Bean 主要用於導入第三方jar或者類
- 包掃描+組件的標註註解(@Component @Controller @Service @Repository),主要用於註冊自己當前項目中的bean
- @Import 快速給容器導入一個組件,相對於@Bean,更靈活.
- 使用Spring提供的FactoryBean注入
常用註解
-
@Configuration
表明這個類是配置類,可以用annotationConfigApplicationContext加載配置類,初始化配置類的配置。
-
@ComponentScan
自動掃描包下的相關注解 可以自定義掃描規則
-
@ComponentScans ComponentScan的集合配置
-
@Scope 配置容器中的實例生成方式
有幾個可選項:- prototype 每次創建一個實例
- singleton 全局只有一個實例
- request 每個請求創建一個實例
- session 每個session會話內共享一個實例
默認是單實例,創建ioc容器的時候,實例bean就被創建了
多實例: 僅當在使用的時候才新建實例
-
@Lazy 單實例bean默認在容器啓動的時候創建對象,如果配置了lazy註解,則會是在使用時候纔會創建並初始化,不在容器啓動的時候創建對象。
-
@Conditional
可以根據條件註冊bean到容器中,不滿足條件就不注入,滿足才注入。例如:實現一個只在windows環境才注入的bean
//1.先自定義一個條件類,用於條件匹配,該類實現Conditon接口 public class LinuxCondition implements Condition { /** * 只在Linux下才注入的匹配規則 * @param context * @param metadata * @return */ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { //獲取beanFactory ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); Environment environment = context.getEnvironment(); //獲取當前java運行的系統環境 String property = environment.getProperty("os.name"); if (property.toUpperCase().contains(("linux".toUpperCase()))) { return true; } return false; } }
//2.使用conditonal註解導入自定義的condition實現類 @Configuration public class MainConfig3 { //張三隻在windows下才會被注入 @Conditional(WinCondition.class) @Bean public Person zhangsan() { return new Person("zhangsan", 11); } //lisi只在windows下才會被注入 @Conditional(LinuxCondition.class) @Bean public Person lisi() { return new Person("lisi", 12); } }
以上代碼在windows環境中指揮注入zhangsan,在linux環境指揮注入lisi
-
@Import
使用方式
-
直接將需要註冊的類放入import中。容器會自動註冊value裏的bean,bean的id爲全類名
@Import(value = {Dog.class, Pig.class})
@Import(value = {Dog.class, Pig.class}) @Configuration public class MainConfig4 { } /如果打印容器中所有bean的id,會發現包含如下結果 //cn.ihu.org.demo4.Dog //cn.ihu.org.demo4.Pig
-
自定義類,繼承ImportSelector,實現selectImports方法。bean的id爲全類名
@Import(value = {CustomSelector.class})
public class CustomSelector implements ImportSelector { public String[] selectImports(AnnotationMetadata importingClassMetadata) { //返回要導入的類的全類名數組 return new String[] {"cn.ihu.org.demo4.Cat", "cn.ihu.org.demo4.Desk"}; } } //如果打印容器中所有bean的id,會發現包含如下結果 //cn.ihu.org.demo4.Cup //cn.ihu.org.demo4.Desk
-
自定義類,繼承ImportBeanDefinitionRegistrar接口,實現registerBeanDefinitions方法,通過 BeanDefinitionRegistry的實例對象向容器中注入bean。
@Import(value = {CustomBeanDefinitionRegistrar.class})
public class CustomBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * @param importingClassMetadata 註解信息 * @param registry 註冊類,把需要加入到容器中的類,加入到容器 */ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { System.out.println(importingClassMetadata.getAnnotationTypes()); //獲取容器中是否註冊了Cup類的實例。 boolean b = registry.containsBeanDefinition("cn.ihu.org.demo4.Cup"); //如果容器中有Cup類註冊進來了,那麼我就再註冊一個Water類進去。 if (b) { //要註冊的bean必須包裝成RootBeanDefinition類 RootBeanDefinition beanDefinition = new RootBeanDefinition(Water.class); //向容器中注入一個water類 registry.registerBeanDefinition("water", beanDefinition); } } }
注意:以上三種方式可以放在一起使用,如 @Import(value = {Dog.class, Pig.class, CustomSelector.class, CustomBeanDefinitionRegistrar.class})
-
-
@Service
-
@Component
-
@Controller
-
@Repository
以上幾個都是用於注入Bean到Spring容器
-
@Value、@PropertySource、@PropertySources
用於對屬性賦值,支持基本字符以及SpringEL表達式
如@Value(#{20-2}) private Integer age; //會注入值 : 18
也可以用於讀取properties文件
//導入配置文件 @PropertySource("clsspath:/test.properties") @Value("${redis.port}") //可以讀取在test.propertes中定義的redis.portd的值
-
@Autowired、 @Qualified 、@Resources(JSR250)、 @Inject(JSR330,需要導入javax.inject)
- @Autowired自動按類型注入,如果有多個同類型的bean被註冊到Spring容器中,則需要結合@Qualified,指明具體使用哪一個bean。
@Autowired可以放在方法,屬性,以及構造方法上,當一個組件只有構造方法時即使不顯示的聲明@autowired,也能夠直接注入。
spring官方推薦在構造方法上使用autowired註解。因爲當spring初始化一個類,會優先使用構造方法創建類之後纔會注入其成員變量。
@Service public class TestService { @Autowired @Qualifier("testDao2") TestDao dao; public TestDao getDao() { return dao; } public void setDao(TestDao dao) { this.dao = dao; } }
- @Primary註解指定注入時的優先級,該bean在注入時會作爲首選項
@Configuration @ComponentScan(basePackages = "cn.ihu.org.demo6") public class Config6 { @Bean @Primary//@Primary註解指定注入時的優先級 public TestDao testDao2() { return new TestDao("2"); } }
- @Resouce 是JSR250的註解,也可以實現依賴注入的功能。
和@Autowire區別是,@Resouce注入的資源必須存在,否則會報錯,而@Autowired可以設置required=false,當資源不存在不會報錯。
@Service public class TestService { @Resource(name = "testDao2") TestDao dao; public TestDao getDao() { return dao; } public void setDao(TestDao dao) { this.dao = dao; } }
- @Inject JSR330中的標準 需要額外引入javax.inject包,支持@Primary優先級,沒有@Autowired(required=false)的功能
- @Autowired自動按類型注入,如果有多個同類型的bean被註冊到Spring容器中,則需要結合@Qualified,指明具體使用哪一個bean。
@Bean
Bean的生命週期
-
創建 -> 初始化-> 銷燬
-
我們可以自定義bean的初始化和銷燬方法
//1.定義一個類 public class Student { public void init() { System.out.println("執行初始化方法..."); }; public void destory() { System.out.println("執行銷燬方法"); } } //2.使用bean初始化時候可以指定初始化和銷燬方法 @Configuration public class Mainconfig5 { @Bean(initMethod = "init", destroyMethod = "destory") public Student student() { return new Student(); } }
-
可以自定義一個類,實現InitializingBean接口,實現afterPropertiesSet方法,在spring容器創建bean,且爲屬性賦值之後,會調用。
自定義一個類,實現DisposableBean接口,實現destroy方法,在bean被銷燬的時候調用。
//創建對應的類 public class Car implements InitializingBean, DisposableBean { /** * 當spring容器銷燬時候,會調用 * @throws Exception */ public void destroy() throws Exception { System.out.println("執行bean銷燬方法"); } /** * Spring容器當中給,當bean創建完成,屬性值賦值完成之後,會調用這個方法 * @throws Exception */ public void afterPropertiesSet() throws Exception { System.out.println("執行bean初始化方法"); } public Car() { System.out.println("創建Bean對象..."); } } //初始化bean @Configuration public class Mainconfig5 { @Bean(initMethod = "init", destroyMethod = "destory") public Student student() { return new Student(); } @Bean public Car car() { return new Car(); } } //spring容器初始化Car類完成,會打印 //執行初始化方法... //創建Bean對象... //執行bean初始化方法
-
可以使用JDK的JSR250標準,使用@PostConstruct、 @PreDestroy
public class School { @PostConstruct public void init() { System.out.println("初始話School"); } @PreDestroy public void destroy() { System.out.println("銷燬school...."); } public School() { System.out.println("創建school..."); } }
-
BeanPostProcessor
可以處理類初始化前後需要做的事情。postProcessBeforeInitialization方法會在bean初始話之前執行,postProcessAfterInitialization會在bean初始化之後執行。
```
//將該processor注入容器後,spring就會在加載bean的時候,在執行bean的初始化方法前後分別調用postProcessBeforeInitialization和postProcessAfterInitialization、
@Component
public class CustomProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization:" + beanName);
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization:" + beanName);
return bean;
}
}
```
Spring中的Aware
Aware接口提供了一種可以通過BeanPostProcessor處理自定義邏輯的方式,在spring初始化BeanPostProcessor之後,對每一個類進行初始化的時候會檢查是否實現了aware接口,然後通過不同的接口調用aware的實現方法。具體過程如下
我們首先定義一個自定義的aware接口實現類,並實現對應方法
@Component
public class CustomAware implements ApplicationContextAware, EnvironmentAware,EmbeddedValueResolverAware {
private ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
System.out.println(resolver.resolveStringValue("{{os.name}}"));
}
@Override
public void setEnvironment(Environment environment) {
System.out.println(Arrays.toString(environment.getActiveProfiles()));
}
public ApplicationContext getContext() {
return context;
}
public void setContext(ApplicationContext context) {
this.context = context;
}
}
我們在測試類中可以看到
public class Demo8ConfigTest {
@Test
public void testAwareInterface() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Demo8Config.class);
CustomAware customAware = context.getBean(CustomAware.class);
System.out.println(context == customAware.getContext());//查看注入的容器是否和啓動的容器相等,結果是true
}
}
Spring中的源碼如下
1.