Spring框架构成
Spring IOC实现原理
- Spring启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册表,然后根据这张注册表实例化Bean,装配好Bean之间的依赖关系,为上层应用提供准备就绪的运行环境。
Bean缓存池
- Spring通过一个配置文件描述Bean之间的依赖关系,利用反射实例化Bean并建立Bean之间的依赖关系。IoC容器在完成这些底层工作的基础上,还提供了Bean实例缓存、生命周期管理、 Bean实例代理、事件发布、资源装载等高级服务。
Bean实例化
- 使用构造方法
- 使用静态方法
- 使用工厂方法
依赖注入方式
构造器注入
public class Boss {
private Car car;
private Office office;
@Autowired
public Boss(Car car ,Office office){
this.car = car;
this.office = office ;
}
…
}
设值(setter)注入
public class Boss {
private Car car;
private Office office;
@Autowired
public void setCar(Car car) {
this.car = car;
}
@Autowired
public void setOffice(Office office) {
this.office = office;
}
…
}
接口注入
循环依赖
- 属性注入 -- 解决循环依赖 -- 通过代理 注入对象, 而非直接注入
- 构造器注入 -- 直接注入, 若存在循环依赖直接在编译启动时暴露出来,构造器注入 对 单元测试 更友好
- 使用构造器注入需要系统有清晰的分层结构,依赖为单向依赖,老系统存在service 之间的相互依赖,存在循环依赖的隐患,不提倡使用构造器注入
Bean作用域
- singleton:在IoC容器中Bean只有一个实例,IoC容器负责负责维护Bean实例生命周期状态。Spring默认使用singleton作用域
- prototype:每次通过getBean方法获Bean时都会产生一个新的Bean实例返回给程序,一旦创建成功,IoC容器不再维护Bean实例生命周期状态
- request:每次HTTP请求将会产生新的Bean实例。只有在Web应用中使用Spring时,该作用域才有效
- session:对于每次HTTP Session,使用session定义的Bean产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效
- globalsession:每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效
Bean自动装配
基于XML装配
- Bean定义:在xml文件中通过
元素定义Bean,如 - Bean注入:通过
子元素或者p命名空间进行注入,如p:userDao-ref = "userDao" - 适用场景:1。Bean实现类来源于第三方类库,如DataSource,JdbcTemplate,因无法在类中标注注解,通过XML配置较好 2.命名空间的配置,如AOP,context等只能采用XML配置
基于注解装配
- Bean定义:在Bean的实现类处标注@Component(@Service,@Constroller和@Repository等)定义Bean
- Bean注入:通过在成员变量或者方法入参标注@Autowired
- 适用场景:Bean的实现类是项目中实现的可直接在Java类中使用基于注解的配置
开启基于注解装配
//配置文件下引入 将隐式地向Spring容器注册后置处理器
//1. AutowiredAnnotationBeanPostProcessor(处理@Autowired)
//2. CommonAnnotationBeanPostProcessor(处理@Resource等)
//3. PersistenceAnnotationBeanPostProcessor
//4. equiredAnnotationBeanPostProcessor
//5.ConfigurationClassPostProcessor((处理@Configuration)
基于Java的配置
- Bean定义:在标注了@Configuration的类中,通过在类方法中标注@Bean定义Bean,方法必须提供Bean的实例化逻辑
- Bean注入:可通过标注@Autowired使方法入参绑定Bean,然后在方法中通过代码注入;还可通过调用配置类的@Bean方法进行注入
- 适用场景:优势在于可通过代码方式控制Bean的初始化逻辑,所以如果实现Bean的逻辑比较复杂则比较适合用基于Java的配置方式
Bean自动装配类型
1.no:这是Spring框架的默认设置,在该设置下自动装配是关闭的,开发者需要自行在bean定义中用标签明确的设置依赖关系
2.byName:该选项可以根据bean名称设置依赖关系。当向一个bean中自动装配一个属性时,容器将根据bean的名称自动在在配置文件中查询一个匹配的bean。如果找到的话,就装配这个属性,如果没找到的话就报错
3.byType:该选项可以根据bean类型设置依赖关系。当向一个bean中自动装配一个属性时,容器将根据bean的类型自动在在配置文件中查询一个匹配的bean。如果找到的话,就装配这个属性,如果没找到的话就报错
4.constructor:造器的自动装配和byType模式类似,但是仅仅适用于与有构造器相同参数的bean,如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常
5.autodetect:该模式自动探测使用构造器自动装配或者byType自动装配。首先,首先会尝试找合适的带参数的构造器,如果找到的话就是用构造器自动装配,如果在bean内部没有找到相应的构造器或者是无参构造器,容器就会自动选择byTpe的自动装配方式
常用注解列举
@Autowired
通常作用范围类成员变量、方法及构造函数,按byType自动注入
@Qualifier
标注对象是成员变量、方法入参、构造函数入参,通常与@Autowired结合使用转换byType为byName注入方式,因为两者的作用范围不同,所以Spring不将@Autowired 和@Qualifier统一成一个注释类
@Resource
通常作用于成员变量、方法入参或构造函数入参,作用相当于@Autowired,不过前者按byType自动注入,@Resource可通过属性设置byName或者byType自动注入方式,默认按byName自动注入
@Bean
指示产生一个bean的方法,并且交给Spring容器管理。使用@Bean注解的好处就是能够动态获取一个Bean对象,能够根据环境不同得到不同的Bean对象。
@Configuration
//@Configuration注解本质上还是@Componen
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
String value() default "";
}
@Configuration 标记的类必须符合下面的要求:
* 配置类必须以类的形式提供(不能是工厂方法返回的实例),允许通过生成子类在运行时增强(cglib 动态代理)。
* 配置类不能是 final 类(没法动态代理)。
* 配置注解通常为了通过 @Bean 注解生成 Spring 容器管理的类。
* 配置类必须是非本地的(即不能在方法中声明,不能是 private)。
* 任何嵌套配置类都必须声明为static。
* @Bean方法不能创建进一步的配置类(也就是返回的bean如果带有@Configuration,也不会被特殊处理,只会作为普通的 bean)
@Component
通过注释定义Bean,取代XML配置文件中定义Bean方式,@Service通常作用在业务层,@Constroller通常作用在控制层,它们与@Component无本质区别
@Repository
通常用于DAO类,该注解不仅将类识别为Bean,同时它还能将所标注的类中抛出的数据访问异常封装为Spring的数据访问异常类型
@Componet与@Configuration的区别
@Component标注的类(包括@Service,@Repository, @Controller)使用@Bean注解和在@Configuration中使用是不同的。在@Component类中使用方法或字段时不会使用CGLIB增强,而在@Configuration类中使用方法或字段时则使用CGLIB创造代理对象
@PostConstruct
假设将对象P注入到对象A,首先生成对象P与对象A才能执行注入。所以如果类A中成员变量p被@Autowired注解,那么注入是发生在A的构造方法执行完之后。如果想在生成对象A时候完成某些初始化操作,而这些初始化操作又依赖于依赖注入,那么就无法在构造函数中实现。@PostConstruct注解的方法将会在依赖注入完成后被自动调用。
Bean生命周期
Bean的生命周期由两组回调(callback)方法组成:
1. 初始化之后调用的回调方法。
2. 销毁之前调用的回调方法。
Spring框架提供了以下四种方式来管理bean的生命周期事件:
* InitializingBean和DisposableBean回调接口
* 针对特殊行为的其他Aware接口
* Xml配置文件中init()方法和destroy()方法
* @PostConstruct和@PreDestroy注解方式
ApplicationContext Bean生命周期
1.首先容器启动后,会对scope为singleton且非懒加载的bean进行实例化
2.按照Bean定义信息配置信息,注入所有的属性
3.如果Bean实现了BeanNameAware接口,会回调该接口的setBeanName()方法,传入该Bean的id,此时该Bean就获得了自己在配置文件中的id
4.如果Bean实现了BeanFactoryAware接口,会回调该接口的setBeanFactory()方法,传入该Bean的BeanFactory,这样该Bean就获得了自己所在的BeanFactory
5.如果Bean实现了ApplicationContextAware接口,会回调该接口的setApplicationContext()方法,传入该Bean的ApplicationContext,这样该Bean就获得了自己所在的ApplicationContext
6.如果有Bean实现了BeanPostProcessor接口,则会回调该接口的postProcessBeforeInitialzation()方法
7.如果Bean实现了InitializingBean接口,则会回调该接口的afterPropertiesSet()方法
8.如果Bean配置了init-method方法,则会执行init-method配置的方法
9.如果有Bean实现了BeanPostProcessor接口,则会回调该接口的postProcessAfterInitialization()方法
10.经过流程9之后,就可以正式使用该Bean了,对于scope为singleton的Bean,Spring的ioc容器中会缓存一份该bean的实例,而对于scope为prototype的Bean,每次被调用都会new一个新的对象,其生命周期就交给调用方管理了,不再是Spring容器进行管理了
11.容器关闭后,如果Bean实现了DisposableBean接口,则会回调该接口的destroy()方法
12.如果Bean配置了destroy-method方法,则会执行destroy-method配置的方法,至此,整个Bean的生命周期结束
BeanFactory Bean生命周期
1.BeanFactory容器中,不会调用ApplicationContextAware接口的setApplicationContext()方法
2.BeanPostProcessor接口的postProcessBeforeInitialzation()方法和postProcessAfterInitialization()方法不会自动调用,必须自己通过代码手动注册
3.BeanFactory容器启动的时候,不会去实例化所有Bean,包括所有scope为singleton且非懒加载的Bean也是一样,而是在调用的时候去实例化
Bean后置处理器
BeanPostProcessor允许在调用初始化方法前后对Bean进行额外的处理。
BeanPostProcessor接口定义回调方法,你可以实现该方法来提供自己的实例化逻辑,依赖解析逻辑等。你也可以在 Spring 容器通过插入一个或多个 BeanPostProcessor 的实现来完成实例化,配置和初始化一个bean之后实现一些自定义逻辑回调方法。
你可以配置多个BeanPostProcessor 接口,通过设置 BeanPostProcessor 实现的Ordered接口提供的order属性来控制这些 BeanPostProcessor 接口的执行顺序
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object var1, String var2) throws BeansException;
Object postProcessAfterInitialization(Object var1, String var2) throws BeansException;
}
Spring框架中的单例Beans是线程安全的么
Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。但实际上,大部分的Spring bean并没有可变的状态(比如Serview类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。
Spring框架中都用到了哪些设计模式
1.代理模式—在AOP和remoting中被用的比较多
2.单例模式—在spring配置文件中定义的bean默认为单例模式
3.模板方法—用来解决代码重复的问题,比如RestTemplate
4.工厂模式—BeanFactory用来创建对象的实例