理论知识
1.切面(aspset):一个关注点的模块化。这个关注点横切多个对象
关注点:事务,数据库连接池,权限控制,日志分析,安全性的处理
2.连接点(Joinponit):程序执行过程中某个特定的点
代理对象调用的方法(完成额外的操作)
3.通知(Advice):在切面某个特定点上的执行的动作
切面中的方法(实现额外操作)
4.切入点(Ponitcut):匹配连接点的断言。
一种匹配规则,满足规则才执行通知
5.目标对象(target):被一个或多个切面通知的对象
真实对象,真实对象的方法—目标方法
不使用注解
在spring-mvc.xml文件中
<!-- aop -->
<bean id="operateLogger" class="aspect.OperateLogger" />
<aop:config>
<!-- <aop:aspect ref="operateLogger">
<aop:before method="log1" pointcut="within(spring.controller..*)"/>
</aop:aspect> -->
<!-- <aop:aspect ref="operateLogger">
<aop:around method="log2" pointcut="within(spring.controller..*)"/>
</aop:aspect> -->
<aop:aspect ref="operateLogger">
<aop:after-throwing method="log3" throwing="e" pointcut="within(spring.controller..*)"/>
</aop:aspect>
</aop:config>
>
- before 前置通知
- around 坏绕通知
- after-throwing 异常通知
throwing=”e” 和形参绑定,e的名字不能随意定,和方法中的形参名一样
在OperateLogger类中
public class OperateLogger {
private Logger logger = Logger.getLogger(this.getClass());
//前置通知方法
public void log1(){
logger.info("--记录用户操作记录");
}
//可加参数
public void log1(JoinPoint p){
logger.info("--记录用户操作记录");
}
//坏绕通知方法
public Object log2(ProceedingJoinPoint p) throws Throwable{
//目标组件的类名
String className = p.getTarget().getClass().getName();
//调用的方法名
String method = p.getSignature().getName();
//获取目标方法
Signature signature = p.getSignature();
MethodSignature methodSignature = (MethodSignature)signature;
Method targetMethod = methodSignature.getMethod();
//当前时间
String date = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").
format(new Date());
//拼写日志
String msg = "-->用户在"+date+",执行了"+className+"."+method+"()";
//记录日志
logger.info(msg);
//执行目标组件的方法
Object obj = p.proceed();
//调用目标组件后也可以处理一些任务
logger.info("-->调用目标组件后的业务方法");
return obj;
}
//异常通知方法
public void log3(Exception e){
StackTraceElement[] elems = e.getStackTrace();
logger.info("-->"+elems[0].toString());
}
//参数变更,JoinPoint必须为第一位参数
public void log3(JoinPoint p,Throwable e){
StackTraceElement[] elems = e.getStackTrace();
logger.info("-->"+elems[0].toString());
}
}
- 前置后置可以接收参数JoinPoint
- 异常通知可以接收JoinPoint,Throwable
<aop:after-returning method="testAfter" pointcut-ref="pc" returning="name" />
//通过后置通知获取返回值,参数名称必须匹配
public void testAfter(String name){
System.out.println("后置通知的获得方法的返回值是"+name);
}
//后置通知
@AfterReturning(value="pointCut()",returning="name")
public void testAfter(String name){
System.out.println("后置通知的获得方法的返回值是"+name);
}
//异常通知
@AfterThrowing(value="pointCut()" , throwing="e" )
public void doException(JoinPoint p,Exception e){
}
注解方式
@Aspect 标注为方面组件
@Before 前置通知
@Around 坏绕通知
@AfterThrowing 异常通知
@AfterReturning 后置通知
@After 最终通知
5大通知只有坏绕通知才能控制目标方法的执行,坏绕通知最强大
开启注解:
<!-- 开启aop组件 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
proxy-target-class=”true”,强制使用cglib创建对象
声明方面组件
@Component
@Aspect
public class OperateLogger {
private Logger logger = Logger.getLogger(this.getClass());
@Before("within(spring.controller..*)")
public void log1(){
logger.info("--记录用户操作记录");
}
//通过空方法定义切入点表达式
@Pointcut(value="within(service..*)")
public void pointCut(){}
@Before("pointCut()")
public void testBefore(){
System.out.println("调用方法前");
}
}
含有注解的切入点
@Around("pointCut() && @annotation(tran)")
public Object transaction(ProceedingJoinPoint p,Transactional tran) throws Throwable{
System.out.println("事务开启");
Object result = p.proceed();
System.out.println("事务提交");
return result;
}
方法上的注解必须是Transactional类型才能被匹配成功,如果没有被匹配成功,这个切入点不被匹配,则不会执行这个切入方法
切入点(pointcut):
1.within(spring.controller..*):表示匹配spring.controller下的所有包
2.execution( 返回值类型 包名 类名 方法名(参数类型1,参数类型2 …) )
- execution(* cn.tarena.ht.service..(..))
- @java.lang.Deprecated * *(..) :任何持有@java.lang.Deprecated注解的方法