什么是spring
spring是开源的轻量级框架,为简化企业级开发而生。spring由八个模块组成,Test,Core Container,AOP,Aspects,Instrumentation,Messaging,Data
Acess,Web组成。spring的特性有IOC(控制反转), DI(依赖注入), AOP(面向切面编程)。
- Core:spring其它组件的核心;
- Beans和Context:是spring控制反转和依赖注入的基础;
- Test:提供了对Junit测试的支持;
- AOP:提供了面向切面编程的支持;
- Aspects:集成了AspectsJ;
- Web:提供web应用程序的支持。
spring的优点
- 方便解耦,简化开发:spring就是一个大对象,可以将所有对象的创建和维护都交给sprig容器来管理;
- 降低了java EE API的使用难度:对那些难用的EE API进行了封装,降低了使用难度;
- 方便集成各种优秀框架:spring不排斥其它优秀的框架,里面提供了对各种优秀框架的支持;
- 方便测试:支持Junit4,可以通过注解方便的测试;
- AOP编程的支持:支持面向切面编程;
- 声明式事务的支持。
IOC
也就是控制反转。在以前如果需要创建对象,就需要我们调用new或者getInstance直接或间接的调用构造方法,有了spring,就实现了解耦,就不需要我们自己创建对象,spring容器会帮我们创建对象,我们只要用就可以了,也不用管是如何创建的,而且如果对象非常多,那对象之间的依赖关系也非常复杂,我们管理起来也非常麻烦,这也都由spring来管理。spring就是一个大工厂,负责创建和管理维护对象。
DI
spring在创建对象时,会调用set()方法或带有参数的构造方法来设置相应的属性值,也就是注入依赖。
AOP
- 通过AOP可以将和业务无关,但各个业务模块都统一调用的逻辑(比如权限拦截,日志管理等)封装起来,就可以大大减少重复的代码,降低各个模块之间的耦合度,也不用侵入原有的业务代码,还具有很好的扩展性,通过AOP将统一的功能抽象出来,在需要调用的地方直接使用,减少重复的代码,增加新的功能也很方便,具有非常好法可扩展性和可维护性。
- AOP在运行时和编译时织入字节码,AOP是基于动态代理的,如果目标类实现了某个接口,就使用jdkProxy来创建对应的代理类,如果没有实现某个接口,就使用CGLIB来创建对应的代理类。
JDK代理的实现原理
核心方法是InvocationHandler接口和Proxy类。InvocationHandler调用invoke方法反射使用目标类的代码,动态的将横切逻辑和业务编织在一起;然后,Proxy通过InvocationHandler生成符合某个接口的实例,生成动态代理对象。
CGLIB代理的实现
因为目标类并没有实现某个接口,但目标类和代理类要兼容,所以生成一个目标类的子类来作为代理类,重写目标类的方法,并添加增强代码。
springAOP和AspectJ的区别
- springAOP是运行时增强的,AspectJ是编译期增强的;
- springAOP是基于代理,AspectJ是基于字节码操作;
- springAOP集成了AspectJ,AspectJ应该算是java生态系统中最完整的AOP框架了,相比于springAOP,AspectJ的功能更加强大,但springAOP更简单一些;
- 如果切面比较少的话,那两者的差异不大,如果切面比较多的话,那还是推荐使用AspectJ,AspectJ比springAOP快很多。
bean的生命周期
- 先在配置文件中找到bean对象的定义;
- 调用javaRelfection API创建bean的实例;
- 如果有属性值就调用set()方法设置属性值;
- 如果bean对象实现了BeanNameAware接口,就调用相应的setBeanName方法,传入bean的name;
- 如果bean对象实现了BeanFactoryAware接口,就调用相应的setBeanFactory方法;
- 如果实现了*.Aware接口,就调用相应的方法;
- 如果有和创建bean的spring容器相关的BeanPostProcessor接口,就调用postProcessBeforeInintialization方法;
- 如果bean对象实现了InitializingBean接口,就调用afterPropertiesSet方法;
- 如果配置文件中有init-method,就调用指定的方法;
- 如果有和创建bean的spring容器相关的BeanPostProcessor接口,就调用postProcessAfterInintialization方法;
- 如果bean实现了DisposableBean接口,就调用相应的distory方法;
- 如果配置文件中有的destory-method,就调用指定的方法。
spring中的bean的作用域
- singleton:单例,只有一个,是默认的bean作用域。
- prototype:原生的,每次都会创建一个新的bean实例。
- request:每个HttpRequest都会创建一个bean实例,每个bean实例只在该HTTPRequest中有效。
- session:每个session都会创建一个bean实例,每个bean实例只在该session中有效。
- global session:全局的session。
spring中的bean单例是线程安全的吗
不是线程安全的,如果多个线程对同一个对象操作时,对对象的非静态实例变量的写操作会有线程安全问题,有两种解决方法:
- 尽量不在bean对象中定义可变的变量,当然也不太现实;
- 可以使用ThreadLocal,将可变的变量定义在ThreadLocal中。
springMVC
- MVC是一种设计模式,springMVC是一种很优秀的MVC框架,使用springMVC可以使我们更简洁的进行web应用的开发,而且springMVC天生和spring框架集成,在springMVC下,一般把项目分成service层(处理业务),DAO层(处理数据库),Entity层(实体),Controller层(接收客户端请求并返回给前端页面)。
springMVC的工作原理
- 客户端发送请求,直接发送到dispatcherServlet;
- dispatcherServlet接收到请求后,调用handlerMapping处理请求,解析请求相应的handler;
- 解析到handler后,就开始调用handlerAdapter处理请求;
- handlerAdapter根据handler调用真正的方法处理请求,并处理相应的业务逻辑;
- handlerAdapter处理完后,返回一个modelAndView对象,model是返回的数据对象,view是逻辑上的view;
- view Resoiver根据逻辑上的view查找实际的view;
- dispatcherServlet将model传给view;
- 将view返回给客户端。
spring中的设计模式
- 工厂设计模式:Bean Factory用到了工厂模式,ApplicationContext也用到了工厂设计模式;
- 单例设计模式:bean对象默认为单例;
- 代理设计模式:spring AOP就用到了代理设计模式;
- 观察者设计模式:spring事件驱动模型;
- 适配器模式:springAOP的增强和通知,spring MVC也用到了适配器模式;
- 模板设计模式:jdbcTemplate用到了模板模式,所有以templates结尾的都是模板设计模式;
- 包装器设计模式:一个项目会连接到不同的数据库,不同的客户请求每次请求的也可能是不同的数据库,包装器设计模式允许我们根据客户的需求动态的切换数据源。
@Component和@Bean的区别
- @Component作用在类上,@Bean作用在方法上;
- @Component通常是通过类路径扫描来自动检测和自动装配到容器中,@Bean通常是在标有该注解的方法中生成bean,告诉spring是某个类的实例,当我们需要时就把它给我们;
- @Bean更具有自定义性,有很多时候只能通过@Bean来生成对象,比如我们引用的第三方类库中的类需要装配到spring容器中只能通过@Bean。
spring管理事务的方式
- 编程式事务,也就是代码;
- 声明式事务,有两种方式:配置和注解。
spring事务的隔离级别
- DEFAULT:使用后端数据库的默认隔离级别,大多数数据库的默认事务隔离级别为READ-COMMITED,mysql数据库的默认隔离级别为REPEATABLE-READ;
- READ-UNCOMMITED:可以读取未提交的事务,会发生脏读,不可重复读和幻读;
- READ-COMMITED:读取已经提交的事务,不会发生脏读,但会发生不可重复读和幻读;
- REPEATABLE-READ:多个事务可以并发读取,并且读取数据一致,但还是会发生幻读;
- SERIALIZABLE:可串行化,是最高的隔离级别。
spring事务的传播行为
支持当前事务:
- REQUIRED:如果当前存在事务,就加入当前事务;如果当前不存在事务,就创建一个新的事务。
- SUPPORTS:如果当前存在事务,就加入当前事务;如果当前不存在事务,就以非事务的方式继续运行。
- MANDATORY:如果当前存在事务,就加入当前事务;如果当前不存在事务,就抛出一个异常。
不支持当前事务:
- REQUIRES-NEW:创建一个新的事务,如果当前存在事务,就挂起当前事务;
- NOT-SUPPORTED:以非事务的方式运行,如果当前存在事务,就挂起当前事务;
- NEVER:以非事务的方式运行,如果当前存在事务,就抛出异常。
其它:
- NESTED:如果当前存在事务,就创建一个事务作为当前事务的嵌套事务来运行;如果不存在事务,就创建一个新的事务。
@Transactional(rollbackFor=Exception.class)
- 可以用在类上或者方法上,如果没有括号里面的,就只会在抛出运行时异常才会回滚,加上后,在遇到非运行时异常也会回滚,保证事务属性。
- 只有用在public修饰的方法,且在外部调用时才会开启事务。