本文是根据JavaGuide的总结复习
SpringIOC/AOP
- 什么是Spring IOC?
- Spring IOC初始化过程
- 什么是Bean
- 什么是AOP,AOP的作用以及实现
- Spring AOP和AspcetJ AOP的区别
- Spring Bean的作用域
- Spring单例Bean的线程安全问题
- @Component 和 @Bean 的区别是什么?
- Bean的生命周期
- SpringMVC是什么?
- SpringMVC的执行流程
- Spring中用到的设计模式
- Spring中的事务的管理方式
- Spring中的事务隔离级别
- Spring中的事务传播
- @Transactional(rollbackFor = Exception.class)注解了解吗?
- JPA是什么?
- 使用JPA在数据库中非持久化一个字段
什么是Spring IOC?
IOC控制反转,其实是设计模式中的依赖倒置思想的实现,将原本在程序中手动创建对象的控制权交给Spring框架来管理。
依赖注入:把底层类作为参数传入上层类,实现上层类对下层类的“控制”。
图片于来源:网络
Spring IOC初始化过程
(1)首先通过ClassPathXmlApplicationContext
获取到所提供的资源文件路径,处理成配置文件数组
(2)调用Refresh
方法进行容器的重建。Refresh
会将原本的Applicationontext
销毁。
(3)在Refresh
方法中:
- 首先进行创建Bean容器前的准备工作,调用
prepareRefrash()
方法。记录启动时间,校验xml文件。 - 创建Bean容器,加载并注册Bean,使用的是**
obtainFreshBeanFactory()
方法。在这个方法中会进行初始化BeanFactory
,加载Bean
,注册Bean
**等工作。但是在这里Bean实例
还没有被创建。
ApplicationContext
继承自BeanFactory
,但是它不应该被理解为 BeanFactory 的实现类
,而是说其内部持有一个实例化的
BeanFactory(DefaultListableBeanFactory
)。以后所有的 BeanFactory 相关的操作其实是委托给这个DefaultListableBeanFactory
实例来处理的。
什么是Bean
从代码层面来讲,就是接口BeanDefinition
的实例。
什么是AOP,AOP的作用以及实现
AOP就是面向切面编程的意思,能够将那些与业务无关,却为业务模块所共同调用的逻辑和责任封装起来。(如:事务处理,日志管理,权限控制等)。便于减少代码重复,降低模块的耦合度,利于扩展性和可维护性。
SpringAOP基于动态代理。
- 如果实现了某个接口,那么SpringAOP使用JDK Proxy去创建代理对象。
- 如果没有实现接口的对象,使用Cglib去生产一个代理对象的子类作为代理。
- 也可以使用AspectJ。AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了
Spring AOP和AspcetJ AOP的区别
- Spring AOP是运行是增强,而AspectJ是编译时增强。
- Spring AOP基于代理,而AspectJ基于字节码操作。
- SpringAOP中集成了AspectJ,当切面很多的时候推荐使用AspectJ
Spring Bean的作用域
- singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
- prototype : 每次请求都会创建一个新的 bean 实例。
- request : 每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。
- session : 每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。
- global-session: 全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。
Spring单例Bean的线程安全问题
单例Bean是存在线程安全问题的。当多个线程操作同一个对象的非静态成员变量时,就会产生线程安全问题。
解决方法:使用ThreadLocal定义成员变量。
@Component 和 @Bean 的区别是什么?
- 作用对象不同:@Component作用于类,而@Bean作用于方法。
- @Component结合@ComponentScan可以很方便的将类装配到Bean容器中。
- @Bean 注解通常是我们在标有该注解的方法中定义产生这个bean的实例,@Bean告诉了Spring这是某个类的示例,当我需要用它的时候还给我。
- 当引入第三方插件或者库需要用@Bean装入Spring容器管理,使用@component不能实现。
Bean的生命周期
SpringMVC是什么?
MVC是一种设计模式,Spring MVC是Spring框架对于MVC模式的运用。SpringMVC主要用于帮助我们进行web开发。MVC模式下,将后端分为了Service层处理业务,Dao层数据库操作,Entity层实体类,Controller层,返回数据给前台。
SpringMVC的执行流程
- 客户端发送请求,请求到
DispatcherServlet
- DispatcherServlet根据请求信息调用的
HandlerMapping
,解析请求对应的Handler
。 - 解析对应的Handler(Controller控制器)以后,开始由H
andlerAdapter
,适配器来进行处理。 - HandlerAdapter根据Handler来调用
真正的处理器
处理请求,和相应的逻辑业务。 - 处理器处理完后,返回一个
ModelandView对象
,Model返回数据对象,View是逻辑上的View。并不是真正展示的视图 ViewResolver
根据返回的View查找实际的View。- DispaterServlet把返回Model传给View视图渲染
- 返回View给客户端
Spring中用到的设计模式
工厂模式:
Spring使用工厂模式可以通过 BeanFactory 或 ApplicationContext 创建 bean 对象。
BeanFactory:延迟注入,使用到某个bean的时候才会进行创建。
ApplicationContext:容器启动时,一次性全部创建bean
单例模式
:
Spring中的Bean的默认作用域就是singleton。
Bean的作用域还有:
Spring实现单例模式的方式:
通过ConcurrentHashMap实现单例注册表的方式实现单例模式。
// 通过 ConcurrentHashMap(线程安全) 实现单例注册表
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "'beanName' must not be null");
synchronized (this.singletonObjects) {
// 检查缓存中是否存在实例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//...省略了很多代码
try {
singletonObject = singletonFactory.getObject();
}
//...省略了很多代码
// 如果实例对象在不存在,我们注册到单例注册表中。
addSingleton(beanName, singletonObject);
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}
//将对象添加到单例注册表
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
}
}
}
代理模式
SpringAOP就是基于代理模式的。
如果代理对象实现了某个接口就是用JDK Proxy去创建代理对象。
如果代理对象没有实现某个接口,就会使用Cglib去生成一个被代理对象实例来进行代理。
Spring中的代理也可以使用AspectJ进行,Spring集成了AspectJ。当切面多的时候就可以使用它。
模板方法
:是一种行为设计模式,它定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。
在Spring中的模板方法使用主要是体现在以Template结尾的数据库操作类中,如JDBCTemplate,HiberbateTemplate
但Spring中对于模板方法模式进行了改进,一般的模板方法都是使用的子类去实现一个操作,而Spring中则是采用Callback模式(回调模式)和模板方法配合使用。
Callback模式(回调模式):把工作流内的某个功能,按照约定的接口暴露给外部使用者,为外部使用者提供数据,或要求外部使用者提供数据。
观察者模式
:是一种对象行为型模式。它表示的是一种对象与对象之间具有依赖关系,当一个对象发生改变的时候,这个对象所依赖的对象也会做出反应。
Spring中的事件驱动模型就是用来这个设计模式。
Spring事件执行流程如下:
(1) 定义一个事件: 实现一个继承自 ApplicationEvent
,并且写相应的构造函数;
(2)定义一个事件监听者:实现 ApplicationListener 接口
,重写 onApplicationEvent() 方法
;
(3)使用事件发布者发布消息: 可以通过ApplicationEventPublisher 的 publishEvent() 方法发布消息
。
适配器模式
:适配器模式(Adapter Pattern) 将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。
SpringAOP的增强或者通知都使用了适配器模式,相关的接口:AdvisorAdapter。
Spring预定义的通知要通过对应的适配器,适配成 MethodInterceptor接口(方法拦截器)类型的对象(如:MethodBeforeAdviceInterceptor 负责适配 MethodBeforeAdvice)。
SpringMVC中的适配器模式:
DispatcherServlet 根据请求信息调用 HandlerMapping,解析请求对应的 Handler。解析到对应的 Handler(也就是我们平常说的 Controller 控制器)后,开始由HandlerAdapter 适配器处理。
-
装饰者模式(包装器模式)
:动态地给对象添加一些额外的属性或行为
Spring 中配置 DataSource 的时候,DataSource 可能是不同的数据库和数据源。这个时候就要用到装饰者模式(这一点我自己还没太理解具体原理)。Spring 中用到的包装器模式在类名上含有 Wrapper或者 Decorator。这些类基本上都是动态地给一个对象添加额外的职责。
- Spring中用到的设计模式:
- 在Spring IOC中,Spring在beanFactory和ApplicationContext中通过工厂模式创建bean对象。
- 代理模式:SpringAOP基于代理模式。
- 适配器模式:SpringAOP的增加或通知使用了适配器模式。SpringMVC中也是用到了适配器模式。(HandlerAdapter)
- 观察者模式:spring的事件模型使用了观察者模式
- 包装器模式:Spring中的DataSource使用了包装器模式动态的给类添加职责。
- 模板方法模式:在Spring中以template结尾的都使用了模板方法模式。如JDBCTemplate
Spring中的事务的管理方式
- 编程式事务,在代码中硬编码的。
- 声明式事务,在配置文件中配置。推荐的使用方式。
声明式事务分为:
XML
注解
Spring中的事务隔离级别
- TransactionDefinition 接口中定义了五个表示隔离级别的常量:
TransactionDefinition.ISOLATION_DEFAULT: 使用后端数据库默认的隔离级别,Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别.
TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
TransactionDefinition.ISOLATION_READ_COMMITTED: 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
TransactionDefinition.ISOLATION_REPEATABLE_READ: 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
Spring中的事务传播
- 支持当前事务的情况:
TransactionDefinition.PROPAGATION_REQUIRED(propagation required): 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
TransactionDefinition.PROPAGATION_SUPPORTS(propagation supports): 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_MANDATORY(propagation mandatory): 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)
- 不支持当前事务
TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。
- 其他情况:
TransactionDefinition.PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。创建一个新的事务
@Transactional(rollbackFor = Exception.class)注解了解吗?
当@Transactional注解作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。如果类或者方法加了这个注解,那么这个类里面的方法抛出异常,就会回滚,数据库里面的数据也会回滚。
在@Transactional注解中如果不配置rollbackFor属性,那么事物只会在遇到RuntimeException的时候才会回滚,加上rollbackFor=Exception.class,可以让事物在遇到非运行时异常时也回滚。
JPA是什么?
JPA(java persistence API)用于管理JavaEE和JavaSE环境中的持久化,以及对象/关系映射的JavaAPI
是处理数据持久化的一个接口,规范
- 实体(pojo)表示关系数据库中的一个表
- 每个实体实例对应着该表中的一行
- 类必须用javax.persistence.Entity注解
类必须含有一个public或者protected的无参构造函数- 当实体实例被当做值以分离对象的方式进行传递(例如通过会话bean的远程业务接口)则该类必须实现Serializable(序列化)接口
- 唯一的对象标志符,简单主键(javax.persistence.Id),复合主键(javax.persistence.EmbeddledId和javax.persistence.IdClass)
使用JPA在数据库中非持久化一个字段
- 改变静态修饰static
- 改变成final修饰
- transient修饰
- @Transient注解修饰