SpringAOP面向切面编程:
aopalliance:联合的开源协作组织,在多个项目间进行协作以期提供一套标准的AOP Java接口
Spring AOP:就是基于AOP Alliance标准API实现的
aspectJ:采用了源代码生成技术来实现AOP。它提供了一套独有的基于Java平台的AOP语法,以及专有的AspectJ编译器。,能够识别诸如aspect,pointcut等特殊关键字,然后利用静态织入的方式.
Spring AOP与AspectJ区别
Spring 允许使用 AspectJ Annotation 用于定义方面(Aspect)、切入点(Pointcut)和增强处理(Advice),Spring 框架则可识别并根据这些 Annotation 来生成 AOP 代理。Spring 只是使用了和 AspectJ 5 一样的注解,但并没有使用 AspectJ 的编译器或者织入器(Weaver),底层依然使用的是 Spring AOP,依然是在运行时动态生成 AOP 代理,并不依赖于 AspectJ 的编译器或者织入器。
AOP 术语:
① Aspect(切面):将关注点提取模块化,最终放到一个类里面如上列SecurityHandler
② Advice(通知):具体横切关注点实现 如:checkSecurity(),包括Before Advice,after Advice,拦截器MethodInterceptor(实现Advice)
③ Pointcut(切入点):应用到 哪些目标对象的,哪些方法上。如:Pointcut(add*)应用到add*方法
④ Weave(织入):将advice应用到目标对象的方法这个过程,术语名称为织入。
⑤ JointPoint(连接点):就是要拦截的方法 如:adduser() 方法
⑥ TargetObject:目标对象UserManagerImpl
拦截:主要通过反射和正则表达式完成
1)JDK动态代理(有接口):实现InvocationHandler的invoke方法
public class SecurityHandler implements InvocationHandler {
private Object targetObject;// 目标对象
// 传入目标对象
public Object newProxy(Object targetObject) {
this.targetObject = targetObject;
// 对目标对象封装,并且返回代理对象(属于目标对象接口)(目标对象类加载器,目标对象接口,自身引用)
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
}
// 代理对象拦截到要执行的方法
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
checkSecurity();
// 目标对象真正执行,有的函数有返回值需要定义ret
Object ret = method.invoke(targetObject, args);
return ret;
}
public void checkSecurity() {
System.out.println("--------安全性检查checkSecurity()-------");
}
}
2)CGLIB代理(无接口,内存临时生成):实现MethodInterceptor (强制使用cglib:<aop:aspectj-autoproxy proxy-target-class="true"/> )
org.aopalliance.intercept.MethodInterceptor:
public class SpringMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before call: " + invocation.getMethod().getName());
Object retVal = invocation.proceed();
System.out.println("after call:");
return retVal;
}
}
import org.springframework.cglib.proxy.MethodInterceptor;
public class SpringAopMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before invoke " + method);
Object result = proxy.invokeSuper(obj, args);
System.out.println("After invoke" + method);
return result;
}
}
AfterReturningAdvice,MethodBeforeAdvice
public class MyAdvice implements AfterReturningAdvice,MethodBeforeAdvice,MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before");
Object obj = invocation.proceed();
System.out.println("after");
return obj;
}
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("我在程序运行之前出现");
}
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("我在程序运行之后出现");
}
}
CGLIB原理:通过底层字节码增强技术动态创建代理类
(CtNewMethod,CtMethod,CtClass,ClassPool)
JdkRegexpMethodPointcut:正则匹配动态代理
<bean id="userManager" class="com.whl.beans.UserManagerImpl"></bean>
<bean id="userCheck" class="com.whl.beans.UserCheck"></bean>
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref bean="userManager"/>
</property>
<property name="interceptorNames"><!-- 拦截器就是通知者(包含advice+pointcut) -->
<list>
<value>advisor1</value>
</list>
</property>
</bean>
<bean id="advisor1" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut" ref="jdkRegexPointcut"/><!-- 切入点正则匹配方法 -->
<property name="advice" ref="userCheck"/>
<!-- advice通知器(必须实现MethodBeforeAdvice或者AfterReturningAdvice或者MethodInterceptor) -->
</bean>
<bean id="jdkRegexPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="patterns">
<list>
<value>.*add.*</value><!-- .代表占位符 -->
<value>.*del.*</value>
</list>
</property>
</bean>
Advisor 包括 pointcut(切入点) ,advice(通知)
扫描注解事务拦截@Transactional
<tx:annotation-driven transaction-manager="transactionManager"/>
<context:component-scan base-package="com.xxx.service,com.yyy.service" />
<!-- 配置事务管理(必须传入sessionFactory,管理事务) -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<!--定义拦截器 -->
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="add*">PROPAGATION_REQUIRED</prop>
<prop key="del*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<!-- 定义目标对象的事务代理对象-->
<bean id="baseServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames">
<list>
<idref bean="transactionInterceptor"/>
</list>
</property>
</bean>
<bean id="userManager" parent="baseServiceProxy">
<!-- 代理接口 -->
<property name="proxyInterfaces">
<value>com.whl.user.manager.UserManager</value>
</property>
<!-- 代理目标对象 -->
<property name="target">
<ref bean=" userManagerBean"/>
</property>
</bean>
<!-- 定义目标对象 -->
<bean id="userManagerBean" class="com.whl.user.manager.UserManagerImpl" autowire="byName"></bean>
事务传播类型:
Required:有则加入,没有开启新事务
Supports:有则加入,没有非事务
Mandatory:有则加入,没有抛异常
Requires_new:总是开启一个新事务,如果已经存在则挂起
Not_supported:总是非事务执行,挂起任务存在事务
Never:总是非事务执行,存在事务抛异常
Nested:如果存在,则嵌套事务,如果没有则
举例:
PROPAGATION_REQUIRED(默认)
在ServiceA.methodA或者在ServiceB.methodB内的任何地方出现异常,事务都会被回滚,因为在一个事务中的。即使ServiceB.methodB的事务已经被 提交,但是ServiceA.methodA在接下来fail要回滚,ServiceB.methodB也要回滚。
PROPAGATION_REQUIRES_NEW(存在于同一事务,任何地方错误都一清回滚):
因为是两个事务:如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚,ServiceB.methodB是不会回滚的。如果ServiceB.methodB失败回滚, 如果他抛出的异常被ServiceA.methodA捕获(系统就不会捕获ServiceA异常,因为异常在ServiceA中已经被拦截),ServiceA.methodA事务仍然可能提交。而如果ServiceA也不捕获,继续上抛。系统会认为ServiceA也抛出异常,所以都要回滚。
/**
* 事务属性配置为 PROPAGATION_REQUIRED
*/
void methodA() {
try {
//savepoint
ServiceB.methodB(); //PROPAGATION_NESTED 级别
} catch (SomeException) {
// 执行其他业务, 如 ServiceC.methodC();
}
}
}
也就是说ServiceB.methodB失败回滚,那么ServiceA.methodA也会回滚到savepoint点上,ServiceA.methodA可以选择另外一个分支,比如ServiceC.methodC,继续执行,来尝试完成自己的事务。
事务隔离级别ISOLATION:
ISOLATION_DEFAULT:默认数据库隔离级别
ISOLATION_READ_UNCOMMITTED:事务最低级别,允许其它事务看到未提交事务数据,产生脏读,不可重读,幻读
ISOLATION_READ_COMMITTED:保证事务只能看到其它事务提交后数据,避免脏读
ISOLATION_REPEATABLE_READ:对相同字段的多次读取的结果是一致的,除非数据被当前事务本身改变。可防止脏读和不可重复读,但幻读仍可发生
ISOLATION_SERIALIZABLE: 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行
可以重复读:对当前字段,同一事务多次读取结果相同除非本身事务修改
幻读: 是对增加或减少记录,如当前事务正在读,其它事务插入一条,当前到就增加一条记录称为幻读