Spring IOC
没有IOC的情况
在没有IOC的情况下,Servlet使用一个service类需要在代码内部显示创建对象,例如下图。如果有多个Servlet同时需要依赖MyService接口调用方法,此时代码的耦合度就会太高。因为后期如果Servlet类调用的是实现MyService接口的NewMyServiceImpl类的话,就导致需要在Servlet类里手动调整。可能会造成错误。(改动代码成本大,改动完的测试成本也很大)。
归根结底,就是代码里各种类之间完全耦合在一起,出现一丁点的变动,都需要改动大量的代码,重新测试,可能还会出现bug。
public class MyServlet {
private MyService myService = new MyServiceImpl();
}
public interface MyService {
}
public class MyServiceImpl implement MyService {
}
public class NewMyServiceImpl implement MyService {
}
Spring IOC
控制反转,依赖注入。
基于注解或者xml文件,将类交由Spring容器工厂。Spring容器根据xml或者注解,去实例化你的一些bean对象,然后根据xml配置或者注解,去对bean对象之间的引用关系,去进行依赖注入,某个bean依赖另外一个bean。
底层核心技术:反射。通过反射技术,直接根据你的类去自己构建对应的对象出来。
系统的类与类之间彻底的解耦合。
public class MyServlet {
@Resource
private MyService myService;
}
// @Service
public class MyServiceImpl implement MyService {
}
@Service
public class NewMyServiceImpl implement MyService {
}
Spring AOP
概念与案例
面向切面编程
有时候,会有多个类的方法都用同样的代码,比如事务代码,都需要有事务开启代码,事务提交代码,事务回滚代码等,此时就可以通过使用AOP,将相同的代码切面出去。后面在执行类的方法的时候,都会去植入一些代码,在所有这些方法刚开始运行的时候,都会去做一些相同的事情(比如开启事务),在所有这些方法运行完毕之后,去根据是否抛出异常等信息去执行植入一些代码(比如提交事务,回滚事务等)。
基于Spring AOP如何切面
AOP的核心原理
动态代理技术。
动态代理相关知识请查阅【java的三种代理方式】。
动态代理
动态代理:其实就是动态地创建一个代理类出来,然后创建这个代理类的实例对象,在代理类对象里面引用委托类,所有的方法的调用,都是先走代理类的对象,它负责做一些代码的增强,再去调用你写的类方法。
Spring AOP使用的就是动态代理技术。
(1)如果你的类实现了某个接口,spring aop会使用jdk动态代理,生成一个跟你实现了同一个接口的代理类,构造一个示例对象出来。
(2)如果你的类没有实现接口,spring aop会改用cglib动态代理,生成一个委托类的子类作为代理类,cglib动态代理可以动态生成字节码,覆盖你的一些方法,在方法里加入增强的代码。
Spring Bean是线程安全的吗
Spring容器bean范围
(1) singleton: 默认,每个容器只有一个bean实例
(2) prototype: 为每一个bean请求提供一个实例
(3) request: 为每一个网络请求创建一个实例,在请求完成
(4) session: 与request范围类似。确保每个session中有一个bean实例,在session过期后,bean就会失效
(5) global_session
Spring Bean不是线程安全
一般来说很少在spring bean存放一些实例变量,一般来说他们都是多个组件互相调用,最终去访问数据库。
@Service
public class MyServiceImpl implement MyService {
public void doService() {
}
}
@Controller
public class MyController {
@Resource
private MyService myService;
public void doRequest() {
myService.doService();
}
}
Spring的事务实现原理和传播机制
事务实现原理
当在代码中加入@Transactional注解,此时spring会使用AOP思想,对你的方法在执行之前,先去开启事务,执行完毕之后,根据你的方法是否报错,来决定回滚或者提交事务。
事务传播机制
@Transactional(propagation = Propagation.REQUIRED)
(1)Propagation.REQUIRED: 如果当前没有事务,就创建一个事务,如果当前存在事务,就加入该事务。(最常用设置)
(2)Propagation.SUPPORTS: 支持当前事务,如果当前存在事务,就加入该事务,否则就以非事务执行。
(3)Propagation.MANDATORY: 支持当前事务,如果当前存在事务,就加入该事务,否则就抛出异常。
(4)Propagation.REQUIRED_NEW: 创建新事务,无论当前存不存在事务,都创建新事务。
(5)Progation.NOT_SUPPORTED: 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
(6)Progation.NEVER: 以非事务方式执行,如果当前存在事务,则抛出异常。
(7)Progation.NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。
嵌套事务:外层的事务如果回滚,会导致内层的事务也回滚;但是内层的事务如果回滚,仅仅回滚自己的代码。
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
doSomethingPre();
methodB();
doSomethingPost();
}
@Transactional(propagation = Propagation.NESTED)
public void methodB {
//to do something
}