Spring容器初始化bean的大概过程,文字总结一下:
如图所示:
IOC就是控制反转,是指创建对象的控制权的转移。以前创建对象的主动权和时机是由自己把控的,而现在这种权力转移到Spring容器中,并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复用。
DI依赖注入,和控制反转是同一个概念的不同角度的描述,即应用程序在运行时依赖IoC容器来动态注入对象需要的外部资源。
最直观的表达就是,IOC让对象的创建不用去new了,可以由spring自动生产,使用java的反射机制,根据配置文件在运行时动态的去创建对象以及管理对象,并调用对象的方法的。
Spring的IOC有三种注入方式 :构造器注入、setter方法注入、根据注解注入。
IoC让相互协作的组件保持松散的耦合,而AOP编程允许你把遍布于应用各层的功能分离出来形成可重用的功能组件。
@Import通过快速导入的方式实现把实例加入spring的IOC容器中,但@Import只能用在类上。@Import注解有三种用法:
@Import({ 类名.class , 类名.class... })
public class TestDemo {
}
对应的import的bean都将加入到spring容器中,这些在容器中bean名称是该类的全类名 ,比如com.yc.类名。
这种方式要求类需要实现ImportSelector接口。
public class Myclass implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 要导入到容器中的组件全类名.
return new String["com.ft.Test.Demo1","com.ft.Test.Demo2"];
}
}
@Configuration
@Import(value={Myclass.class})
public class Config {
}
这种方式要求类需要实现ImportBeanDefinitionRegistrar接口。
public class Myclass implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
//指定bean定义信息(包括bean的类型、作用域...)
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(TestDemo.class);
//注册一个bean指定bean名字(id)
beanDefinitionRegistry.registerBeanDefinition("testDemo",rootBeanDefinition);
}
}
@Configuration
@Import(value={Myclass.class})
public class Config {
}
从源代码可以看到@Controller, @Service, @Repository这三个注解上都有@Component这个注解,四个注解最大的区别就是使用的场景和语义不一样,按类的角色选择相应的注解即可。
@Configuration注解提供了全新的bean创建方式。这个注解搭配@Bean、@Autowired等注解,可以完全不依赖xml配置,在运行时完成bean的创建和初始化工作。例如:
//@Configuration申明了AppConfig是一个配置类
@Configuration
public class AppConfig {
// 自动注入Demo
@Autowired
public Demo demo;
//@Bean注解申明了一个bean,bean名称默认为方法名testBean
@Bean
TestBean testBean(){
return new TestBean();
}
}
从@Configuration注解的源码里面可知,@Configuration 标记了@Component元注解,因此可以被@ComponentScan扫描并处理,在Spring容器初始化时Configuration类会被注册到Bean容器中,最后还会实例化。
在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的;但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂bean,它的实现与设计模式中的工厂模式、修饰模式类似。
BeanFactory:
定义了IOC容器的最基本形式,并提供了IOC容器应遵守的最基本的接口。Spring中有很多种不同类型的BeanFactory,比如ApplicationContext,ClassPathXmlApplicationContext、AnnotationConfigApplicationContext等等。
FactoryBean:
FactoryBean是Spring容器中的一个对象,专门用来创建对象特殊的对象,一般情况下Spring都是通过反射来创建对象的,但是如果某个对象的创建过程过于复杂或无法按照传统的方式实例化,就可以使用FactoryBean。需要实现FactoryBean中的getObject( )、getObjectType( )。
Spring提供了两种后置处理Bean的扩展接口,分别为BeanPostProcessor和BeanFactoryPostProcessor。这两者在使用上是有区别的。
BeanPostProcessor:后置处理Bean,它是bean级别的,可以在Spring Bean初始化之前和之后对Bean或者程序进行增强。有两个方法:
BeanFactoryPostProcessor:主要用于增强工厂的功能,可以在创建Spring Bean之前修改相关Bean的元信息。有一个方法:
两者都是接口,同时,InstantiationAwareBeanPostProcessor继承于BeanPostProcessor。
BeanPostProcessor有两个方法:
InstantiationAwareBeanPostProcessor有两个方法:
Spring对单例对象支持循环依赖,其实现原理在于使用了三级缓存:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory =
this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
假设A依赖B,B依赖A,Spring循环依赖的流程图如下所示:
在Spring开发中,程序员需要进行二次开发,那么程序员就需要获取到Spring内部的组件,这时就需要用到XXXAware接口。比如BeanNameAware、BeanFactoryAware、ApplicationContextAware,就可以为自定义的类分别注入Bean的ID、BeanFactory、ApplicationContext。程序员使用这些信息,进行功能开发。
// TestDemo就可以获得TestDemo在Spring中的nameID。
public class TestDemo implements BeanNameAware {
private String nameId;
@Override
public void setBeanName(String name) {
nameId = name;
}
}
// TestDemo就可以获得BeanFactory。
public class TestDemo implements BeanFactoryAware {
private BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}
// TestDemo就可以获得ApplicationContext。
public class TestDemo implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
Spring容器中的bean可以分为5个范围:
与OOP对比,AOP是处理一些横切性问题,这些横切性问题不会影响到主逻辑的实现,但是会散落到代码的各个部分,难以维护。AOP就是把这些横切问题和主逻辑分开,达到与主业务逻辑解耦的目的。
在配置类上开启AOP功能@EnableAspectJAutoProxy,
当配置了@EnableAspectJAutoProxy时,Spring就会注册一个代理的Creator对象(AspectJAwareAdvisorAwareProxyCreator),在创建目标对象前,找到切面,并将其缓存起来,创建对象时就会判断目标对象是否满足切点的要求,满足则会产生代理对象,不满足则返回原对象。
事务的传播特性指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。
Spring总共给出了7中事务传播特性:
总结:
死活不要事务的
PROPAGATION_NEVER:没有就非事务执行,有就抛出异常
PROPAGATION_NOT_SUPPORTED:没有就非事务执行,有就直接挂起,然后非事务执行
可有可无的
PROPAGATION_SUPPORTS: 有就用,没有就算了
必须有事务的
PROPAGATION_REQUIRES_NEW:有没有都新建事务,如果原来有,就将原来的挂起。
PROPAGATION_NESTED: 如果没有,就新建一个事务;如果有,就在当前事务中嵌套其他事务。
PROPAGATION_REQUIRED: 如果没有,就新建一个事务;如果有,就加入当前事务。
PROPAGATION_MANDATORY: 如果没有,就抛出异常;如果有,就使用当前事务。
通过AOP方式实现一个代理对象,通过TransactionInterceptor对事务方法进行拦截,在拦截的过程中会解析出事务的属性,然后把事务的属性存在缓存里,当执行这些方法的时候,拦截器就会自动找到对应方法的事务属性,再根据事务的隔离级别去判断是否需要开启新事务、是否在原有事务中进行、还是抛出异常等,作出相应正确的处理,最后执行目标方法,目标方法执行结束后,会选择回滚事务或提交事务。
在这个过程中会涉及到事务挂起,事务挂起是把之前的事务信息存在一个对象中,并放在当前事务状态对象中,等待新事务执行完之后,会选择恢复挂起的事务。