Spring IOC
IOC(Inversion of Control),即控制反转,IOC意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制;即由容器来帮忙创建及注入依赖对象。
DI(Dependency Injection),即依赖注入,控制反转是通过依赖注入实现的,IOC是设计思想,DI是实现方式。
- BeanFactory
- ApplicationContext
- GenericApplicationContext
是初始化的时候就创建容器,往后的每次refresh都不会更改 - AbstractRefreshableApplicationContext
AbstractRefreshableApplicationContext及子类的每次refresh都是先清除已有(如果不存在就创建)的容器,然后再重新创建;AbstractRefreshableApplicationContext及子类无法做到GenericApplicationContext混合搭配从不同源头获取bean的定义信息 - FileSystemXmlApplicationContext
从文件系统下加载上下文定义,适用于xml配置的方式 - ClassPathXmlApplicationContext
从类路径下加载上下文定义,适用于xml配置的方式 - AnnotationConfigApplicationContext
基于java的配置类中加载上下文定义,适用java注解的方式 - ConfigurableApplicationContext
扩展于 ApplicationContext,它新增加了两个主要的方法: refresh()和 close(),让 ApplicationContext 具有启动、刷新和关闭应用上下文的能力
- GenericApplicationContext
- BeanDefinition
定义了各种Bean对象及其相互的关系
IOC初始化
IoC初始化的流程,是把最终的将Bean的定义即BeanDefinition放到beanDefinitionMap中
Spring AOP
AOP(Aspect Oriented Programming),即面向切面编程。
Spring AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib ,这时候Spring AOP会使用 Cglib 生成一个被代理对象的子类来作为代理
Spring Bean生命周期
- 实例化(Instantiation)
- 属性赋值(Populate)
- 初始化(Initialization)
// 分别调用Bean实现的XXXAware接口的接口方法、Bean实现InitializingBean接口的afterPropertiesSet方法、Bean实现的init_method方法 - 销毁(Destruction)
调用DisposableBean接口的destory方法
getBean->doGetBean->createBean->doCreateBean
doCreateBean方法分别调用下面三个方法:
->createBeanInstance
->populateBean
->initializeBean
refresh->finishBeanFactoryInitialization->getBean
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
// 调用Aware方法
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
// 调用Aware方法
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//遍历调用BeanPostProcessor的BeanPostProcessor方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 分别调用InitializingBean的afterPropertiesSet方法、init_method方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//遍历调用BeanPostProcessor的BeanPostProcessor方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
InstantiationAwareBeanPostProcessor继承了BeanPostProcessor接口,InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation方法在doCreateBean之前调用,也就是在bean实例化之前调用的,这也是Aop等功能实现的关键点。
InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation方法在populateBean方法里面开始属性填充之前调用。
SpringMVC
Spring设计模式
- 工厂方法
FactoryBean接口 - 工厂模式
Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象 - 代理模式
Spring AOP 功能的实现 - 单例模式
Spring 中的 Bean 默认都是单例的 - 模板方法模式
Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式 - 装饰器模式
Spring 中用到的包装器模式在类名上含有 Wrapper或者 Decorator。这些类基本上都是动态地给一个对象添加一些额外的职责 - 适配器模式
SpringMVC中的适配器HandlerAdatper - 观察者模式
Spring 事件驱动模型
// 定义一个事件,继承自ApplicationEvent并且写相应的构造函数
public class DemoEvent extends ApplicationEvent{
private static final long serialVersionUID = 1L;
private String message;
public DemoEvent(Object source,String message){
super(source);
this.message = message;
}
public String getMessage() {
return message;
}
// 定义一个事件监听者,实现ApplicationListener接口,重写 onApplicationEvent() 方法;
@Component
public class DemoListener implements ApplicationListener<DemoEvent>{
//使用onApplicationEvent接收消息
@Override
public void onApplicationEvent(DemoEvent event) {
String msg = event.getMessage();
System.out.println("接收到的信息是:"+msg);
}
}
// 发布事件,可以通过ApplicationEventPublisher 的 publishEvent() 方法发布消息。
@Component
public class DemoPublisher {
@Autowired
ApplicationContext applicationContext;
public void publish(String message){
//发布事件
applicationContext.publishEvent(new DemoEvent(this, message));
}
}
Spring事务失效
事务传播机制:
- REQUIRED
如果当前上下文中存在事务,那么加入该事务,如果不存在事务,创建一个事务,这是默认的传播属性值。 - SUPPORTS
如果当前上下文存在事务,则支持事务加入事务,如果不存在事务,则使用非事务的方式执行。 - MANDATORY
如果当前存在一个事务,则加入该事务;否则,抛出异常 - REQUIRES_NEW
创建一个新的事务,并且如果存在一个事务,则将该事务挂起 - NOT_SUPPORTED
以非事务方式执行操作,如果当前存在一个事务,则将该事务挂起 - NEVER
以非事务方式执行操作,如果当前存在一个事务,则抛出异常 - NESTED
如果当前存在一个事务,则在嵌套事务内执行。如果没有事务,则按 REQUIRED传播级别执行。嵌套事务是外部事务的一部分,可以在外部事务提交或回滚时部分提交或回滚
@Transational事务失效场景:
方法不是public方法
方法用final、static修饰
如果一个方法被声明为 final或者 static,则该方法不能被子类重写,也就是说无法在该方法上进行动态代理,这会导致 Spring无法生成事务代理对象来管理事务同一个类中,方法内部调用
解决方法:被调用方法拆到新的Service类、注入自己、AopContext.currentProxy()获取代理对象事务注解被覆盖导致事务失效
多线程调用
不同线程获取的数据库连接不一样,从而是两个不同的事务异常被捕获并处理了,没有重新抛出
手动抛了别的异常
因为Spring默认只处理 RuntimeException和Error,对于普通的 Exception不会回滚,除非,用 rollbackFor属性指定配置。
解决方案:添加属性配置 @Transactional(rollbackFor = Exception.class)
@Autowire、@Resource区别
- 出处不一样
@Autowire 是Spring定义注解,与Spring强耦合,其它框架用不了。
@Resoure是JSR-250提供的Java标准,绝大部分框架都支持。 - 注解应用地方不一样
@Autowired能够用在:构造器、方法、参数、成员变量和注解上。
@Resource能用在:类、成员变量和方法上。 - 装配方式不一样
@Autowire默认按byType自动装配,如果要使用byName,需要使用@Qualifier一起配合。
而@Resource默认byName自动装配,如果指定了name,则用byName自动装配,如果指定了type,则用byType自动装配,如果同时指定name和type,查找唯一匹配的bean。