Spring中的AOP,数据开发及事务管理
AOP的概念
Spring的通知类型
• org. aopall iance. intercept. Method I nterceptor (环绕通知) 在目标方法执行前后实施增强,可以应用于曰志、事务管理等功能。
• org.springframework.aop.MethodBeforeAdvice (前置通知) 在目标方法执行前实施增强,可以应用于权限管理等功能。
• org.springframework.aop.AfterReturningAdvice (后置通知) 在目标方法执行后实施增强,可以应用于关闭流、上传文件、删除临时文件等功能。
• org.springframework.aop.ThrowsAdvice (异常通知) 在方法抛出异常后实施增强,可以应用于处理异常记录曰志等功能。
• org .springframework.aop.1 ntroduction I nterceptor (引介通知) 在目标类中添加一些新的方法和属性,可以应用于修改老版本程序(增强类)。
ProxyFactoryBean
ProxyFactoryBean 是 FactoryBean 接口的实现类, FactoryBean 负责实例化一个 Bean ,而 ProxyFactoryBean 负责为其他 Bean 创建代理实例。 在 Spring 中,使用 ProxyFactoryBean 是 创建 AOP 代理的基本方式。
对 ProxyFactoryBean 类有了初步的了解后,接下来通过一个典型的环绕通知案例,来演示 Spring 使用 ProxyFactoryBean 创建 AOP 代理的过程
建一个ASpect类
public class CalcAspect {
/**
* 计算方法耗时
* 环绕通知
* @param joinPoint 代表连接点对象,该对象可以获取被代理方法的所有信息
*/
public Object aroundM(ProceedingJoinPoint joinPoint) throws Throwable {
// 获取连接点代表的方法的签名
Signature signature = joinPoint.getSignature();
log.debug("[aroundM] ---- 目标方法signature: " + signature);
String methodName = signature.getName();
Object[] args = joinPoint.getArgs();
log.debug("[aroundM] ---- 目标方法"+methodName+"("+ Arrays.toString(args)+")开始执行");
long start = System.currentTimeMillis();
// 调用目标方法
Object retVal = joinPoint.proceed();
// 插入我们自己的逻辑代码
long timer = System.currentTimeMillis() - start;
log.debug("[aroundM] ---- 目标方法["+methodName+"("+ Arrays.toString(args)+")]执行结束,返回值: "+retVal+", 耗时: " + timer + "ms.");
// 正常返回目标方法的返回值
return retVal;
}
public void beforeM() {
log.debug("[beforeM] ---- 目标方法开始执行");
}
public void afterReturningM(Object retVal) {
log.debug("[afterReturningM] ---- 目标方法执行结束,返回值: " + retVal);
}
public void afterFinallyM() {
log.error("[afterFinallyM] ---- 方法执行结束");
}
public void afterThrowing(Throwable throwable) {
log.error("[afterThrowing] ---- 方法执行出错", throwable);
}
}
创建接口Clac
public interface Calc {
public int add(int num1, int num2);
public int minus(int num1, int num2);
public int multiply(int num1, int num2);
}
创建ClackImpl
public class CalcImpl implements Calc {
@Override
public int add(int num1, int num2) {
long start = System.currentTimeMillis();
int result = num1 + num2;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
long timer = System.currentTimeMillis() - start;
System.out.println("方法执行结束, 耗时:" + timer + "ms.");
return result;
}
public int minus(int num1, int num2) {
// 模拟方法执行报错,便于看到after-throwing通知
// int ret = 9 / 0;
return num1 - num2;
}
public int multiply(int num1, int num2) {
log.info("执行multiply方法");
return num1 * num2;
}
}
MyClacProxy代理
public class MyCalcProxy extends CalcImpl{
@Override
public int multiply(int num1, int num2) {
System.out.println("multiply 方法开始执行");
int result = super.multiply(num1, num2);
System.out.println("multiply 方法执行结束");
return result;
}
}
XML文件配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<!-- calc 代表了原生的业务代码(将来被切入的对象) -->
<bean id="calc" class="com.lanou3g.spring.simple.calc.CalcImpl"/>
<!-- 切面类, 定义了我们要插入进去的代码。(将来会被织入到目标类中) -->
<bean id="calcAspect" class="com.lanou3g.spring.simple.calc.CalcAspect"/>
<aop:config>
<!-- 这里仅演示可以在<aop:config>标签内配置多个切入点表达式和切面(同样的切面切入两次没有什么实际意义) -->
<aop:pointcut id="all_calc_method" expression="execution(* com.lanou3g.spring.simple.calc.CalcImpl.*(..))"/>
<!--<aop:pointcut id="all_calc_method2" expression="execution(* com.lanou3g.spring.simple.calc.CalcImpl.*(int, String))" />-->
<aop:aspect ref="calcAspect">
<aop:around method="aroundM" pointcut-ref="all_calc_method"/>
<aop:before method="beforeM" pointcut-ref="all_calc_method"/>
<aop:after-returning method="afterReturningM" pointcut-ref="all_calc_method" returning="retVal"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="all_calc_method" throwing="throwable"/>
<aop:after method="afterFinallyM" pointcut-ref="all_calc_method"/>
</aop:aspect>
</aop:config>
</beans>
测试类
public class AppByTransactionXml {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("tx_conf.xml");
testQuery(ctx);
testTransaction(ctx);
}
static void testQuery(ApplicationContext ctx) {
TeacherDaoImpl teacherDao = ctx.getBean(TeacherDaoImpl.class);
List<Teacher> teacherList = teacherDao.queryAll();
for(Teacher teacher : teacherList) {
System.out.println("id: " + teacher.getId()+", tname: " + teacher.getTname());
}
}
static void testTransaction(ApplicationContext ctx) {
TeacherDaoImpl teacherDao = ctx.getBean(TeacherDaoImpl.class);
int rowEffect = teacherDao.insertTeacher(new Teacher("女儿国王"));
System.out.println("影响了" + rowEffect + "行.");
}
}