目录
一、IOC与DI
IOC和DI是一个概念,依赖注入,即当某个角色需要另外一个角色协助的时候,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在spring中,创建被调用者的工作不再由调用者来完成,创建(在spring容器启动的时候,spring会把你在配置文件中配置的bean都初始化好,然后在你需要调用的时候,就把它已经初始化好的那些bean分配给你需要调用这些bean的类)被调用者的工作由spring来完成,然后注入调用者,因此称为控制反转。
spring以动态灵活的方式来管理对象 , 注入的三种方式,构造方法注入、setter注入、基于注解的注入。
构造注入的优点:可以在构造器中决定依赖关系的顺序。
设置注入的优点:直观,自然
spring提供了许多IOC容器的实现,比如XmlBeanFactory,ClasspathXmlApplicationContext,其中XmlBeanFactory就是针对最基本的ioc容器的实现,这个IOC容器可以读取XML文件定义的BeanDefinition(XML文件中对bean的描述)
IOC容器的初始化包括BeanDefinition的Resource定位、载入和注册这三个基本的过程。
二、AOP
AOP可以说是对OOP的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。(将相同逻辑的重复代码横向抽取出来,使用动态代理技术将这些重复代码织入到目标对象方法中,实现和原来一样的功能。这样一来,我们就在写业务时只关心业务代码,而不用关心与业务无关的代码)
Spring AOP默认是使用JDK动态代理,如果代理的类没有接口则会使用CGLib代理。
如果是单例的我们最好使用CGLib代理,如果是多例的我们最好使用JDK代理。
原因:JDK在创建代理对象时的性能要高于CGLib代理,而生成代理对象的运行性能却比CGLib的低。
①spring aop xml方式。
<aop:config>
<aop:pointcut expression="execution(* com.aop.impl.xml.ArithmeticCalculator.*(..))" id="pointcut"/>
<aop:aspect ref="logging" order="1">
<aop:before method="beforeMethod" pointcut-ref="pointcut"/>
<aop:after method="afterMethod" pointcut-ref="pointcut"/>
<aop:after-returning method="afterReturnning" returning="result" pointcut-ref="pointcut"/>
<aop:after-throwing method="afterThrowing" throwing="ex" pointcut-ref="pointcut"/>
<!-- <aop:around method="aroundMethod" pointcut-ref="pointcut"/> -->
</aop:aspect>
<aop:aspect ref="validation" order="2">
<aop:before method="validation" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
②spring aop 注解方式。
AspectJ的AOP与Spring的区别
AspectJ在编译时就增强了目标对象(在编译阶段将Aspect织入Java字节码中, 运行的时候就是经过增强之后的AOP对象),Spring AOP的动态代理则是在每次运行时动态的增强,生成AOP代理对象,区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。
三、事务的传播行为
ServiceA{
methodA(){
for(int i=0;i<=1i++){
serviceB.methodB();
}
}
}
ServiceB(){
@Transcational
methodB(){
}
}
methodB的事务隔离级别 | ServiceA的methodA()中存在事务 | ServiceA的methodA()中没有事务 | 描述 |
Propagation.REQUIRED | 在methodA的事务中运行 | 给methodA启动一个新的事务,但是在methodB的事务中运行 | 如果调用方有事务在运行,那么当前方法就在这个事务中运行,否则就为调用方重新启动一个新的事务,并且在被调用方法的事务中运行。 |
Propagation.REQUIRES_NEW | 为methodA开启一个新的事务,但是在methodB的事务中运行 | 为methodA开启一个新的事务,但是在methodB的事务中运行 | 无论如何为调用方开启一个新的事务, 但是在被调用方的事务内运行. 如果当前有事务在运行, 就应该先挂起它. |
Propagation.SUPPORTS | 在methodA的事务中运行 | 在methodB的事务中运行 | 如果调用方有事务在运行,当前的方法就在这个事务内运行,否则他可以不运行在调用者的事务中(在被调用方的事务内运行) |
Propagation.REQUIRED:
Propagation.REQUIRES_NEW:
四、Spring 声明式事务和编程式事务
1、编程式事务使用TransactionTemplate或者直接使用底层的PlatformTransactionManager,需要手动开启事务和提交事务。对于编程式事务管理,spring推荐使用TransactionTemplate。
2、声明式事务是建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。两种方式:
①基于tx和aop名字空间的xml配置文件
<!-- 配置事务属性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="purchase" propagation="REQUIRES_NEW"/><!-- 指定重开事务的方法 -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务切入点,以及把事务切入点和事务属性关联起来 -->
<aop:config>
<aop:pointcut expression="execution(* tx.xml.service.*.*(..))" id="txPointCut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
②使用@Transactional注解
<!-- 配置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 启动事务注解 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
五、@Autowire和@Resource的区别
@Autowire bytype进行匹配,如果有多个匹配的类型,使用@Qualifiter 指定注入 Bean 的名称(不指定会报错)
@Resource名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名,按照名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。