一、spring Bean的生命周期
生命周期可以分为以下几步:
- 通过Spring框架的beanFactory工厂利用反射机制创建bean对象。
- 根据set方法或者有参构造方法给bean对象的属性进行依赖注入。
- 判断当前bean对象是否实现相关aware接口,诸如beanNameAware、beanFactoryAware接口,如果有的话执行对应的方法。
- 执行bean对象的前置处理器postprocessbeforinitialztion。
- 执行初始化方法initMethod。
- 执行bean对象的后置处理器postprocessafterinitialztion。
- 判断当前bean对象是否为单例,是则放到spring对象容器中,多例则直接返回bean对象。
- 使用bean对象
- 关闭容器,调用destroy方法销毁对象。
二、Spring事务在以下几种情况下会失效。
- 直接new出来的对象添加事务不起作用,因为只有Spring定义的bean才接受事务。
- 由于MySQL的引擎用Myisam不支持事务,所以如果使用MySQL的Myisam引擎的话,事务不起作用。
- 如果@Transaction注解到非public方法上,事务不起作用,这是因为Spring的Aop特性。
- 如果在当前类中进行内部调用方法,比如在A类中有a方法和b方法,a方法没有加@Transation, b方法加了@Transation,在方法a中调用方法b,方法b中的事务也不会生效。这是因为Spring在扫描bean的时候会自动为标注了@Transaction注解类生成一个代理类,在有注解方法被调用时,实际是代理类调用的,代理类在调用之前会开启事务,执行事务操作。但是同类中的方法相互调用,相当于this.b(),此时的b方法并非代理类调用,而是直接通过原有的bean直接调用,所以注解不起作用。
- 开启的线程中。
- 被final注释
- 异常类型错误,如果抛出的runtimeException事务才会回滚。
- 如果异常被catch到,必须要抛出异常,事务才会回滚。
注:Spring事务是通过面向切面实现的,源码在TransactionInterceptor类中。事务开启是依赖数据库链接的,而链接是和线程绑定的。嵌套事务通过savepoint实现,事务方法中开启新事务则通过获取新的链接进行事务开启(实际就是关闭自动提交)。
链接对象封装在TransactionInfo中,它也记录了前一个事务对象,如果没有则为null。
每开启一个事务,这个事务对象都会绑定到一个ThreadLocal静态变量中,即当前的事务对象。
spring事务切面基于以上逻辑实现了声明式事务管理,及事务属性的传播(在当前存在或不存在事务时,加入当前事务或开启新的事务或以非事务方式执行或在嵌套事务中执行)。
所以在事务方法中
1.使用新的线程执行代码逻辑,会使事务失效。
2.事务方法内部捕获了异常sql的异常,未将抛出到事务切面中,这时候事务会提交,即正常执行的那部分sql执行结果将会生效。
3.未指定回滚的异常,默认是RuntimeException回滚。如果抛出编译期异常,则事务最终也会提交,不会回滚。
三、设计模式在源码中应用
工厂方法模式:在Spring的AbstractBeanFactory
抽象工厂模式:在Spring的BeanFactory
单例模式:Spring中创建单例。
建造者模式:解析xml文件
原型模式:在创建ioc容器后,通过getBean()获取bean对象时,往里追可以发现在核心方法处spring对bean的scope属性进行了判断,配置了prototype时。
适配器模式:spring AOP中的MethodBeforeAdviceAdapter类。
装饰模式:TransactionAwareCacheDecorator 类
代理模式:spring中代理有两种,Jdk代理方式和CGLIB。
外观模式:Tomcat 中,catalina.jar 中的 RequestFacade 和 ResponseFacade 。
桥接模式:JDBC
组合模式:***positeCacheManager,Mybatis 在处理 xml 动态 sql 中用到了。
享元模式:String常量池, Integer 的静态内部类 IntegerCache。
策略模式:Cglib2AopProxy和JdkDynamicAopProxy分别代表两种策略的实现方式。
模板方法模式:JdbcTemplate实现了一系列常用的数据访问的算法骨架。
观察者模式: ApplicationListener, ContextLoaderListener等。
迭代器模式:集合。
责任链模式:handler,filter,Intercept。
命令模式:Tomcat 中命令模式在 Connector 和 Container 组件之间有体现。
备忘录模式:spring-webflow 中的stateManageableMessageContext.createMessageMemento()
状态模式:spring-statemachine spring状态机
访问者模式:Spring中的 BeanDefinitionVisitor 类主要用于访问 BeanDefinition。
中介者模式:java web 开发中 MVC 模式(Model-View-Controller)就用到了中介者模式,Controller 就是 Model 和 View 的中介
解释器模式:在 Spring中,ExpressionParser 接口内部采用的是解释器模式。
四、Spring是如何解决循环依赖的?
三级缓存,简单来说,A创建过程中需要B,于是A将自己放到三级缓存里面,去实例化B。B实例化的时候发现需要A,于是B先查一级缓存,没有再查二级缓存,还是没有则再查三级缓存。找到了A然后把三级缓存里面的这个A放到二级缓存里面,并删除三级缓存里面的A,B顺利初始化完毕,将自己放到一级缓存里面(此时B里面的A依然是创建中状态)然后回来接着创建A,此时B已经创建结束,直接从一级缓存里面拿到B,然后完成创建,并将A放到一级缓存中。
注:一级缓存放的是成品对象,二级缓存放的是半成品对象,三级缓存放的是因AOP、getBean的lambda表达式。
五、Spring自动装配bean有哪些方式?
在 Spring 中,自动装配(autowiring)是指由 Spring 容器自动将符合条件的 bean 注入到其他 bean 中的过程。Spring 提供了以下几种自动装配方式:
1. 通过注解(Annotation-based):
@Autowired:这是 Spring 中最常用的自动装配注解,可以用在构造函数、方法、属性和参数上。默认情况下,它按照类型进行自动装配。如果存在多个符合条件的 bean,可以通过 @Qualifier 注解指定具体的 bean。
@Inject:这是一个来自 Java CDI(Contexts and Dependency Injection)规范的注解,用法与 @Autowired 类似。需要额外引入 javax.inject 依赖。
@Resource:这是一个来自 Java EE 的注解,可以指定 bean 的名称进行自动装配。如果没有指定名称,它会根据类型进行自动装配。
2. 通过 XML 配置(XML-based):
autowire="byName":通过属性名自动装配。如果 Spring 容器中存在一个与需要装配属性同名的 bean,则将其注入。
autowire="byType":通过类型自动装配。如果 Spring 容器中存在一个与需要装配属性相同类型的 bean,则将其注入。如果存在多个相同类型的 bean,将会抛出异常。
autowire="constructor":通过构造函数自动装配。会根据构造函数参数的类型,将容器中相应类型的 bean 注入。如果存在多个相同类型的 bean,将会抛出异常。
autowire="autodetect":自动检测自动装配方式。首先尝试通过构造函数自动装配,如果失败,则尝试通过类型自动装配。
尽管 XML 配置方式仍然可用,但现代的 Spring 应用程序通常更倾向于使用注解方式进行自动装配,因为它更简洁、灵活且易于维护。