1. Spring事务
spring的事务实现原理
Spring事务将connection放入到当前线程的threadlocal中,spring中使用ThreadLocal来设计TransactionSynchronizationManager类,实现了事务管理与数据访问服务的解耦,同时也保证了多线程环境下connection的线程安全问题。
2.Spring bean的作用域
类别 | 说明 |
---|---|
singletone:单例 | 在spring中仅存在一个Bean实例,Spring默认为单例模式。 |
prototype:原型模式 | 每次通过Spring容器获取prototype定义的bean时,容器都将创建一个新的Bean实例,每个Bean实例都有自己的属性和状态。 |
request:请求模式 | 在一次Http请求中,容器会返回该Bean的同一实例,而对不同的Http请求则会产生新的Bean,而且该bean仅在当前Http Request内有效。 |
session:会话模式 | 在一次Http Session中,容器会返回该Bean的同一实例。而对不同的Session请求则会创建新的实例,该bean实例仅在当前Session内有效。 |
global Session:全局会话模式 | 在一个全局的Http Session中,容器会返回该Bean的同一个实例,仅在使用portlet context时有效。 |
2. Spring AOP
AOP(Aspect Oriented Programing)指面向切面编程,是通过预编译和运行时动态代理实现的一种技术。
2.1 AOP 相关概念
1.连接点:join point
指Java程序中的具有边界性质的特定位置,如类初始化之前,类初始化之后,方法调用前和方法调用后等。目前Spring仅支持类方法这样的join point,可以在方法前,方法后这样的连接点织入(weaving)增强(advice)。
2.切点:point cut
AOP把类方法作为查询条件,通过point cut找到连接点(join point),即让切点来筛选连接点,如目标类有5个方法, 程序只想让3个方法实现增强,剩余的2个不需要增强,那个就通过point cut从5个方法中,筛选出需要增强的3个方法。
3.通知:advice
advice是织入到目标类方法(即join point)的程序代码块,并且制定要织入的连接点的方位(方法前,方法后等),advice主要有AfterAdvice,BeforeAdvice,ThrowAdvice,MethodInterceptor和AfterReturningAdvice等。
4.目标对象:Target
advice的增强代码织入的目标类。
5.引入:Introduction
Introduction为类添加属性或者方法,这样是一些类在没有实现某些接口的情况下,动态的添加该接口的实现。
6.织入:weaving
织入是指将advice添加到目标类方法(即连接点)上的过程,Spring采用动态代理织入,AspectJ采用编译器期间和类加载期间织入。
7.代理:proxy
目标类被织入advice后,形成一个新的代理类,该代理类同时具有目标类和advice的功能。
8.切面:Aspect
切面包含了point cut和advice组成,point cut指定了在什么地方干(指定增强的目标类方法),advice指定了干什么(增强代码块)和什么时候(before or after)干。
2.2 Java代理模式
可参考如下文章:
1.设计模式(4)-代理模式
2.Java代理(Proxy)模式
这里不再赘述。
2.3 AOP 实现原理
AOP目前有两种实现方式:
1.静态代理:静态代理可以实现编译时增强,即在程序编译阶段就生成AOP代理对象。AspectJ就是使用了静态代理的方式;
2.动态代理:动态代理可以实现运行时增强,即在程序运行时使用JDK动态代理或者Cglib代理(Code Generation Library,即代码生成包,所以也可以称为动态字节码增强代理
),临时生成AOP代理类。Spring AOP就是使用的动态代理。
2.1JDK动态代理:
JDK动态代理是针对接口的代理,只有接口方法才能够被代理,主要使用的JDK的rt.jar中的java.lang.reflect.Proxy代理类和java.lang.reflect.InvocationHandler调用程序接口。Proxy代理类内部有一个属性InvocationHandler h
package java.lang.reflect;
public class Proxy implements Serializable {
protected InvocationHandler h;
protected Proxy(InvocationHandler var1) {
Objects.requireNonNull(var1);
this.h = var1;
}
@CallerSensitive
public static Class> getProxyClass(ClassLoader var0, Class... var1) throws IllegalArgumentException {
...
...
}
@CallerSensitive
public static Object newProxyInstance(ClassLoader classLoader, Class>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
...
...
}
}
其中:
ClassLoader classLoader:指类加载器;
Class>[] interfaces:获得的全部接口;
InvocationHandler h: 得到InvocationHandler接口的子类实例。
InvocationHandler.java
public interface InvocationHandler {
/**
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
其中:
Object proxy:指被代理的对象;
Method method:要调用的proxy的方法;
Object[] args: 指调用target目标类的方法的参数。
JDK动态代理的主要思路:
将InvocationHandler接口的子类封装成一个proxy的最终操作类,替换到target目标类,然后通过invoke(Object proxy, Method method, Object[] args)方法执行对target目标类的增强代码块和target目标类的方法。JDK动态代理只是在创建动态代理时,将被代理接口和InvocationHandler的实现类进行关联,当proxy执行被代理的target的方法时,通过InvocationHandler的invoke方法来执行。
JDK动态代理的缺点:
JDK动态代理的Proxy类的 public static Object newProxyInstance(ClassLoader classLoader, Class>[] interfaces, InvocationHandler h)方法中,interfaces限制了target必须是接口或者接口的实现。如果类没有实现接口,那么只能使用Cglib代理了。
2.2 Cglib动态代理:
Cglib动态代理采用字节码技术,为target目标类创建一个子类,Override需要被代理的方法,并在子类中采用方法拦截的技术,拦截所有父类的方法调用,然后织入advice代码块。理解Cglib代理的原理后,也就明白target目标类不能是final类,而且被代理的方法不能是private,final和static的。
Cglib动态代理主要用到了cglib-***.jar包中的net.sf.cglib.proxy.MethodInterceptor接口和net.sf.cglib.proxy.Enhancer接口,其中MethodInterceptor继承了net.sf.cglib.proxy.Callback接口,当调用代理对象方法的时候会交给callback对象的来处理。
MethodInterceptor接口:
package net.sf.cglib.proxy;
import java.lang.reflect.Method;
public interface MethodInterceptor extends Callback {
Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy ) throws Throwable;
}
其中:
Object proxy:指子类代理对象;
Method method:要调用的方法的反射对象;
Object[] args:指传递给method的参数;
MethodProxy methodProxy:cglib生成的用来代替method对象的。
Cglib的核心是实现MethodInterceptor接口,使用intercept()方法进行面向切面的处理,调用相应的增强advice。