文章目录
- 1. Spring 概述(基本情况)
- 1.1 Spring 的优势
- 1.2 Spring 的核⼼结构
- 2. 核⼼思想 IoC 和 AOP
- 2.1 什么是IoC?
- 2.2 什么是AOP
- 2.3 AOP在解决什么问题
- 3. Spring IoC ⾼级应⽤
- 3.1 BeanFactory与ApplicationContext区别
- 3.1.1 BeanFactory
- 3.1.2 ApplicationContext
- 3.1.3区别总结
- 3.2 DI 依赖注⼊的注解实现⽅式
- 3.3 常用注解
- 3.4 lazy-Init 延迟加载
- 3.5 FactoryBean 和 BeanFactory
- 3.5.1 FactoryBean
- 3.6 后置处理器
- 3.6.1 BeanPostProcessor
- 3.6.2 BeanFactoryPostProcessor
- 3.7 循环依赖问题
- 3.7.1 循环依赖处理机制
- 4. Spring AOP ⾼级应⽤
- 5. Spring 声明式事务的⽀持
- 5.1 事务的四⼤特性
1. Spring 概述(基本情况)
Spring 是分层的 full-stack(全栈) 轻量级开源框架,以 IoC 和 AOP 为内核,提供了展现层 Spring MVC 和业务层事务管理等众多的企业级应⽤技术,还能整合开源世界众多著名的第三⽅框架和类库,已
经成为使⽤最多的 Java EE 企业应⽤开源框架。
1.1 Spring 的优势
- ⽅便解耦,简化开发 通过Spring提供的IoC容器,可以将对象间的依赖关系交由Spring进⾏控制,避免硬编码所造成的 过度程序耦合。⽤户也不必再为单例模式类、属性⽂件解析等这些很底层的需求编写代码,可以更 专注于上层的应⽤。
- AOP编程的⽀持 通过Spring的AOP功能,⽅便进⾏⾯向切⾯的编程,许多不容易⽤传统OOP实现的功能可以通过 AOP轻松应付。
- 声明式事务的⽀持 @Transactional可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式⽅式灵活的进⾏事务的管理,提⾼ 开发效率和质量。
- ⽅便程序的测试可以⽤⾮容器依赖的编程⽅式进⾏⼏乎所有的测试⼯作,测试不再是昂贵的操作,⽽是随⼿可做的 事情。
- ⽅便集成各种优秀框架Spring可以降低各种框架的使⽤难度,提供了对各种优秀框架(Struts、Hibernate、Hessian、 Quartz等)的直接⽀持。 降低JavaEE API的使⽤难度 Spring对JavaEE API(如JDBC、JavaMail、远程调⽤等)进⾏了薄薄的封装层,使这些API的使⽤ 难度⼤为降低。
1.2 Spring 的核⼼结构
Spring是⼀个分层⾮常清晰并且依赖关系、职责定位⾮常明确的轻量级框架,主要包括⼏个⼤模块:
- 数据处理模块
- Web模块
- AOP(Aspect Oriented Programming)/Aspects模块
- Core Container模块
- Test 模块
Spring核⼼容器(Core Container) 容器是Spring框架最核⼼的部分,它管理着Spring应⽤中 bean的创建、配置和管理。在该模块中,包括了Spring bean⼯⼚,它为Spring提供了DI的功能。 基于bean⼯⼚,我们还会发现有多种Spring应⽤上下⽂的实现。所有的Spring模块都构建于核⼼
容器之上。
2. 核⼼思想 IoC 和 AOP
2.1 什么是IoC?
IoC Inversion of Control (控制反转/反转控制),注意它是⼀个技术思想,不是⼀个技术实现
描述的事情:Java开发领域对象的创建,管理的问题 传统开发⽅式:⽐如类A依赖于类B,往往会在类A中new⼀个B的对象IoC思想下开发⽅式:我们不⽤⾃⼰去new对象了,⽽是由IoC容器(Spring框架)去帮助我们实例化对
象并且管理它,我们需要使⽤哪个对象,去问IoC容器要即可
我们丧失了⼀个权利(创建、管理对象的权利),得到了⼀个福利(不⽤考虑对象的创建、管理等⼀系列 事情)
为什么叫做控制反转?
控制:指的是对象创建(实例化、管理)的权利
反转:控制权交给外部环境了(spring框架、IoC容器)
IoC解决对象之间的耦合问题
2.2 什么是AOP
AOP: Aspect oriented Programming ⾯向切⾯编程/⾯向⽅⾯编程 AOP是OOP的延续
从OOP说起OOP三⼤特征:封装、继承和多态 oop是⼀种垂直继承体系
2.3 AOP在解决什么问题
在不改变原有业务逻辑情况下,增强横切逻辑代码,根本上解耦合,避免横切逻辑代码重复
3. Spring IoC ⾼级应⽤
3.1 BeanFactory与ApplicationContext区别
BeanFactory 和 ApplicationContext 都是 Spring Framework 中用于管理和获取 Bean
对象的核心接口,它们之间有一些重要的区别。
3.1.1 BeanFactory
定义和作用:
BeanFactory 是 Spring 框架中最基础的接口,提供了 IoC (控制反转) 和 DI (依赖注入) 的核心功能。它负责实例化、配置和管理 Spring Bean。
它是 Spring IoC 容器的基础接口,定义了获取 Bean 的基本方法,如 getBean() 等。
延迟初始化:
BeanFactory 采用延迟初始化策略,即在第一次请求获取 Bean 时才会进行实例化和初始化。
功能简单:
功能相对较少,主要提供了 IoC 容器的基本功能,适用于对资源和性能有较高要求的环境。
典型实现类:
典型的 BeanFactory 实现类是 XmlBeanFactory,已在 Spring 5.x 中标记为过时,推荐使用 ApplicationContext 代替。
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
MyBean bean = (MyBean) beanFactory.getBean("myBean");
3.1.2 ApplicationContext
定义和作用:
ApplicationContext 是 BeanFactory 的子接口,它增加了更多的企业级功能。除了提供 BeanFactory 的所有功能外,还提供了更多的企业级特性,如国际化支持、事件发布机制、资源加载、AOP 支持等。
预加载和缓存:
ApplicationContext 在启动时会预加载所有的单例 Bean,并且提供了更好的性能和内存管理,因为它会缓存所有的 Bean 实例。
功能丰富:
除了 BeanFactory 的功能外,还提供了更多的企业级特性,使得 Spring 应用程序更加易于开发和管理。
典型实现类:
典型的 ApplicationContext 实现类有 ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、AnnotationConfigApplicationContext 等。
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
MyBean bean = (MyBean) context.getBean("myBean");
3.1.3区别总结
- 延迟初始化 vs 预加载:
BeanFactory 采用延迟初始化,只在需要时才实例化 Bean。
ApplicationContext 在启动时会预加载所有的单例 Bean,并且可以提供更好的性能和内存管理。
- 功能范围:
BeanFactory 提供了基本的 IoC 容器功能。
ApplicationContext 在 BeanFactory 的基础上增加了更多的企业级特性,如事件发布、AOP 支持、国际化支持等。
- 适用场景:
如果应用对性能要求较高,可以使用 BeanFactory。
如果需要更多的企业级特性或者对性能要求不那么敏感,建议使ApplicationContext。
3.2 DI 依赖注⼊的注解实现⽅式
@Autowired(推荐使⽤) @Autowired为Spring提供的注解,需要导⼊包 org.springframework.beans.factory.annotation.Autowired。 @Autowired采取的策略为按照类型注⼊。
public class TransferServiceImpl { @Autowired private AccountDao accountDao;
}
如上代码所示,这样装配回去spring容器中找到类型为AccountDao的类,然后将其注⼊进来。这 样会产⽣⼀个问题,当⼀个类型有多个bean值的时候,会造成⽆法选择具体注⼊哪⼀个的情况, 这个时候我们需要配合着@Qualifier使⽤。
@Qualifier告诉Spring具体去装配哪个对象。
@Resource @Resource 注解由 J2EE 提供,需要导⼊包 javax.annotation.Resource。
@Resource 默认按照 ByName ⾃动注⼊。
@Resource 在 Jdk 11中已经移除,如果要使⽤,需要单独引⼊jar包
3.3 常用注解
@Configuration 注解,表名当前类是⼀个配置类
@ComponentScan 注解,替代 context:component-scan
@PropertySource,引⼊外部属性配置⽂件 @Import 引⼊其他配置类 @Value 对变量赋值,可以直接赋值,也可以使⽤ ${} 读取资源配置⽂件中的信息
@Bean 将⽅法返回对象加⼊ SpringIOC 容器
3.4 lazy-Init 延迟加载
Bean的延迟加载(延迟创建)
ApplicationContext 容器的默认⾏为是在启动服务器时将所有 singleton bean 提前进⾏实例化。提前 实例化意味着作为初始化过程的⼀部分,ApplicationContext 实例会创建并配置所有的singletonbean。
- 开启延迟加载⼀定程度提⾼容器启动和运转性能
- 对于不常使⽤的 Bean 设置延迟加载,这样偶尔使⽤的时候再加载,不必要从⼀开始该 Bean 就占 ⽤资源
3.5 FactoryBean 和 BeanFactory
BeanFactory接⼝是容器的顶级接⼝,定义了容器的⼀些基础⾏为,负责⽣产和管理Bean的⼀个⼯⼚, 具体使⽤它下⾯的⼦接⼝类型,⽐如ApplicationContext;此处我们重点分析FactoryBean
Spring中Bean有两种,⼀种是普通Bean,⼀种是⼯⼚Bean(FactoryBean),FactoryBean可以⽣成 某⼀个类型的Bean实例(返回给我们),也就是说我们可以借助于它⾃定义Bean的创建过程。
Bean创建的三种⽅式中的静态⽅法和实例化⽅法和FactoryBean作⽤类似,FactoryBean使⽤较多,尤其在Spring框架⼀些组件中会使⽤,还有其他框架和Spring框架整合时使⽤
3.5.1 FactoryBean
- 定义和作用:
FactoryBean 是一个接口,用于在 Spring 容器中定义和配置复杂的 Bean 实例化逻辑。它允许自定义 Bean 的实例化过程,而不受限于标准的构造函数或静态工厂方法。
实现 FactoryBean 接口的类必须实现 getObject() 方法,该方法返回一个由该工厂创建的实际 Bean 实例。
-
自定义 Bean 实例化过程:
FactoryBean 提供了更高级别的控制和定制化,允许程序员在创建 Bean 实例时执行自定义逻辑。 -
实现步骤:
创建一个实现 FactoryBean 接口的类,并实现 getObject() 方法,定义如何创建 Bean 实例。
在 Spring 配置文件中声明该 FactoryBean 的 Bean 定义。
3.6 后置处理器
Spring提供了两种后处理bean的扩展接⼝,分别为 BeanPostProcessor 和 BeanFactoryPostProcessor,两者在使⽤上是有所区别的。
3.6.1 BeanPostProcessor
在Bean对象实例化(并不是Bean的整个⽣命周期完成)之后可以使⽤BeanPostProcessor进⾏后置处理做⼀些事情
定义⼀个类实现了BeanPostProcessor,默认是会对整个Spring容器中所有的bean进⾏处理。如果要对
具体的某个bean处理,可以通过⽅法参数判断,两个类型参数分别为Object和String,第⼀个参数是每
个bean的实例,第⼆个参数是每个bean的name或者id属性的值。所以我们可以通过第⼆个参数,来判断我们将要处理的具体的bean。
package com.xxx;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
/** * @Author 应癫
* @create 2019/12/3 16:59 */
public class MyBeanPostProcessor implements BeanPostProcessor {
public MyBeanPostProcessor() { System.out.println("BeanPostProcessor 实现类构造函数...");
}
@Override public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException { if("xxx".equals(beanName)) { System.out.println("BeanPostProcessor 实现类 postProcessBeforeInitialization ⽅法被调⽤中......"); }
return bean; }
@Override public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException { if("xxx".equals(beanName)) { System.out.println("BeanPostProcessor 实现类 postProcessAfterInitialization ⽅法被调⽤中......"); }
return bean; }
}
3.6.2 BeanFactoryPostProcessor
在BeanFactory初始化之后可以使⽤BeanFactoryPostProcessor进⾏后置处理做⼀些事情
BeanDefinition对象:我们在 XML 中定义的 bean标签,Spring 解析 bean 标签成为⼀个 JavaBean,
这个JavaBean 就是 BeanDefinition 注意:调⽤ BeanFactoryPostProcessor
⽅法时,这时候bean还没有实例化,此时 bean 刚被解析成BeanDefinition对象
package com.xxx;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor; importorg.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
/** * @Author 应癫
* @create 2019/12/3 16:56 */
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public MyBeanFactoryPostProcessor() { System.out.println("BeanFactoryPostProcessor的实现类构造函数...");
}
@Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println("BeanFactoryPostProcessor的实现⽅法调⽤中......");
}
}
3.7 循环依赖问题
循环依赖其实就是循环引⽤,也就是两个或者两个以上的 Bean 互相持有对⽅,最终形成闭环。⽐如A 依赖于B,B依赖于C,C⼜依赖于A。
Spring中循环依赖场景有:
- 构造器的循环依赖(构造器注⼊)
- Field 属性的循环依赖(set注⼊)
3.7.1 循环依赖处理机制
- 单例 bean 构造器参数循环依赖(⽆法解决)
- prototype 原型 bean循环依赖(⽆法解决)
- 单例bean通过setXxx或者@Autowired进⾏循环依赖
Spring 的循环依赖的理论依据基于 Java 的引⽤传递,当获得对象的引⽤时,对象的属性是可以延后设置的,但是构造器必须是在获取引⽤之前
Spring通过setXxx或者@Autowired⽅法解决循环依赖其实是通过提前暴露⼀个ObjectFactory对 象来完成的,简单来说ClassA在调⽤构造器完成对象初始化之后,在调⽤ClassA的setClassB⽅法之前就把ClassA实例化的对象通过ObjectFactory提前暴露到Spring容器中。
4. Spring AOP ⾼级应⽤
spring 实现AOP思想使⽤的是动态代理技术 默认情况下,Spring会根据被代理对象是否实现接⼝来选择使⽤JDK还是CGLIB。当被代理对象没有实现 任何接⼝时,Spring会选择CGLIB。当被代理对象实现了接⼝,Spring会选择JDK官⽅的代理技术,不过
我们可以通过配置的⽅式,让Spring强制使⽤CGLIB。
连接点:⽅法开始时、结束时、正常运⾏完毕时、⽅法异常时等这些特殊的时机点,我们称之为连接 点,项⽬中每个⽅法都有连接点,连接点是⼀种候选点
切⼊点:指定AOP思想想要影响的具体⽅法是哪些,描述感兴趣的⽅法 Advice增强:
第⼀个层次:指的是横切逻辑
第⼆个层次:⽅位点(在某⼀些连接点上加⼊横切逻辑,那么这些连接点就叫做⽅位点,描述的是具体 的特殊时机)
Aspect切⾯:切⾯概念是对上述概念的⼀个综合 Aspect切⾯= 切⼊点(@pointcut)+增强
= 切⼊点(锁定⽅法) + ⽅位点(锁定⽅法中的特殊时机)+ 横切逻辑
5. Spring 声明式事务的⽀持
5.1 事务的四⼤特性
- 原⼦性(Atomicity) 原⼦性是指事务是⼀个不可分割的⼯作单位,事务中的操作要么都发⽣,要么都 不发⽣。
从操作的⻆度来描述,事务中的各个操作要么都成功要么都失败
-
⼀致性(Consistency)
事务必须使数据库从⼀个⼀致性状态变换到另外⼀个⼀致性状态。 例如转账前A有1000,B有1000。转账后A+B也得是2000。 ⼀致性是从数据的⻆度来说的,(1000,1000) (900,1100),不应该出现(900,1000) -
隔离性(Isolation)
事务的隔离性是多个⽤户并发访问数据库时,数据库为每⼀个⽤户开启的事务, 每个事务不能被其他事务的操作数据所⼲扰,多个并发事务之间要相互隔离。
⽐如:事务1给员⼯涨⼯资2000,但是事务1尚未被提交,员⼯发起事务2查询⼯资,发现⼯资涨了2000 块钱,读到了事务1尚未提交的数据(脏读) -
持久性(Durability)
持久性是指⼀个事务⼀旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发⽣故障也不应该对其有任何影响。
@EnableTransactionManagement