很常见的知识点,也是面试题,简单列一列吧
1、Spring 容器根据配置中的 bean 定义 实例化 bean。
2、Spring 使用依赖注入填充所有属性,如 bean 中所定义的配置。
3、invokeAwareMethods:如果 bean 实现BeanNameAware 接口,则工厂通过传递 bean 的 ID 来调用setBeanName()。
如果bean实现BeanClassLoaderAware,则调用setBeanClassLoader()
4、如果 bean 实现 BeanFactoryAware 接口,工厂通过传递自身的实例来调用 setBeanFactory()。
5、如果存在与 bean 关联的任何BeanPostProcessors,则调用 preProcessBeforeInitialization() 方法
6、如果为 bean 指定了 init 方法( 的 init-method 属性),那么将调用它。
7、最后,如果存在与 bean 关联的任何 BeanPostProcessors,则将调用 postProcessAfterInitialization() 方法
8、如果 bean 实现DisposableBean 接口,当 spring 容器关闭时,会调用 destory()。
9、如果为bean 指定了 destroy 方法( 的 destroy-method 属性),那么将调用它。
基于接口的编程+策略模式+配置文件
在Springboot的自动装配过程中,最终会加载META-INF/spring.factories文件,而加载的过程是由SpringFactoriesLoader加载的。从CLASSPATH下的每个jar包中搜索所有META-INF/spring.factories
配置文件,其实这里不仅仅是去ClassPath路径下查询,而是会扫描所有路径下的jar包,只不过这个文件只会在ClassPath下的jar包中
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
// spring.factories文件的格式为:key=value1,value2,value3
// 从所有的jar包中找到META-INF/spring.factories文件
// 然后从文件中解析出key=factoryClass类名称的所有value值
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
// 取得资源文件的URL
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
List<String> result = new ArrayList<String>();
// 遍历所有的URL
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
// 根据资源文件URL解析properties文件,得到对应的一组@Configuration类
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
String factoryClassNames = properties.getProperty(factoryClassName);
// 组装数据,并返回
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
return result;
}
PROPAGATION_REQUIRED
支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
比如说,ServiceB.methodB的事务级别定义为PROPAGATION_REQUIRED, 那么由于执行ServiceA.methodA的时候,
ServiceA.methodA已经起了事务,这时调用ServiceB.methodB,ServiceB.methodB看到自己已经运行在ServiceA.methodA
的事务内部,就不再起新的事务。而假如ServiceA.methodA运行的时候发现自己没有在事务中,他就会为自己分配一个事务。
这样,在ServiceA.methodA或者在ServiceB.methodB内的任何地方出现异常,事务都会被回滚。即使ServiceB.methodB的事务已经被
提交,但是ServiceA.methodA在接下来fail要回滚,ServiceB.methodB也要回滚
PROPAGATION_SUPPORTS
–支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY
–支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW
–新建事务,如果当前存在事务,把当前事务挂起,执行当前新建事务完成以后,上下文事务恢复再执行。
PROPAGATION_NOT_SUPPORTED
–以非事务方式执行操作,如果当前存在事务,就把当前事务挂起,执行当前逻辑,结束后恢复上下文的事务。
PROPAGATION_NEVER
–以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行
先调用构造函数进行实例化,然后填充属性,再接着进行其他附加操作和初始化,正是这样的生命周期,才有了Spring的解决循环依赖,这样的解决机制是根据Spring框架内定义的三级缓存来实现的,也就是说:三级缓存解决了Bean之间的循环依赖
后面分析下代码
找出了前面提到的三级缓存,也就是三个Map集合类:
singletonObjects:第一级缓存,用于保存实例化、注入、初始化完成的bean实例
earlySingletonObjects:第二级缓存,用于保存实例化完成的bean实例
singletonFactories:第三级缓存,用于保存bean创建工厂,以便于后面扩展有机会创建代理对象。属于提前暴露
所以当一个Bean调用构造函数进行实例化后,即使属性还未填充,就可以通过三级缓存向外暴露依赖的引用值(所以循环依赖问题的解决也是基于Java的引用传递),这也说明了另外一点,基于构造函数的注入,如果有循环依赖,Spring是不能够解决的。
还要说明一点,Spring默认的Bean Scope是单例的,而三级缓存中都包含singleton,可见是对于单例Bean之间的循环依赖的解决,Spring是通过三级缓存来实现的
不可以,主要是为了生成代理对象。
因为三级缓存中放的是生成具体对象的匿名内部类,他可以生成代理对象,也可以是普通的实例对象。
使用三级缓存主要是为了保证不管什么时候使用的都是一个对象。
假设只有二级缓存的情况,往二级缓存中放的显示一个普通的Bean对象,BeanPostProcessor去生成代理对象之后,覆盖掉二级缓存中的普通Bean对象,那么多线程环境下可能取到的对象就不一致了
Spring 框架支持以下五种 bean 的作用域:
BeanFactory和ApplicationContext有什么区别?
ApplicationContext 继承自 BeanFactory
两者都是Spring提供的IOC容器。BeanFacotory也被称为基本IOC,而ApplicationContext被称为高级IOC。ApplicationContext包括BeanFactory的所有功能并提供了额外的功能
BeanFactory:是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。ApplicationContext接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:
①继承MessageSource,因此支持国际化。
②统一的资源文件访问方式。
③提供在监听器中注册bean的事件。
④同时加载多个配置文件。
⑤载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。
BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。
ApplicationContext,它是在容器启动时,一次性创建了所有的Bean
BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建
BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。
Spring 框架中都用到了哪些设计模式?
(1)工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例;
(2)单例模式:Bean默认为单例模式。
(3)代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;
(4)模板方法:用来解决代码重复的问题。比如.JdbcTemplate
(5)观察者模式:ApplicationListener。
(6)适配器模式:Aop中,使用Advice(通知)来增强被代理类的功能
@Autowire和@Resource的区别
1.@Autowire是Spring开发的,而@Resource是jdk开发的
2.@Autowire是按照type来注解的,而@Resource是按照名称来的,如果名称找不到,那么就按照type
如果指定了名字查不到会报错,不会按type
使用@Autowired 注解来自动装配指定的 bean。在使用@Autowired 注解之前需要在 Spring 配置文
件进行配置。
在启动 spring IoC 时,容器自动装载了一个 AutowiredAnnotationBeanPostProcessor 后置处理器,
当容器扫描到@Autowied、@Resource 或@Inject 时,就会在 IoC 容器自动查找需要的 bean,并装
配给该对象的属性。在使用@Autowired 时,首先在容器中查询对应类型的 bean:
• 如果查询结果刚好为一个,就将该 bean 装配给@Autowired 指定的数据;
• 如果查询的结果不止一个,那么@Autowired 会根据名称来查找;
• 如果上述查找的结果为空,那么会抛出异常。解决方法时,使用 required=false。
祝你好运~~