发表于: 2018-01-06 18:19:33
0 599
今天完成的事:
学习Aspectj实现AOP
遇到的困难:
1、利用注解向指定方法织入通知时,无参的方法可以成功,有参的方法没有成功,试了很久。
原因:切入点表达式写的不对,缺少方法中的 ..
@Around("execution(* * ..ServiceImpl.*(..))")
对于无参的方法不写 .. 可以,但是有参的必须写,否则切入点表达式不完整。
2、【未解决】之前写好的项目,现在启动tomcat运行,出现
Error:Cannot build artifact 'task2springmvc:war exploded' because it is included into a circular dependency (artifact 'task2springmvc:war exploded', artifact 'task2-springmvc:war exploded')
我百度这个问题的解释是,循环依赖,即A依赖B,B依赖C,C依赖A,或者是A依赖于B,B依赖A
单元测试可以正常运行
pom文件中新加的两个jar包注释掉了,新加的类和之前的东西也没有关系,还是有这个问题
问题可能在,但是这里没办法删除啊
明天计划:
收获:
1、什么是Aspectj?
AOP面向切面编程是一种思想,spring框架可以实现,Aspectj框架也可以实现,并且支持注解式开发,所有Spring框架引入了Aspectj框架。
一、注解式:
2、Aspectj的切入点表达式
@Around是环绕通知
@Around("execution(* * ..ServiceImpl.*(..))")
切入点表达式
execution()
返回值类型,方法名(参数名)是不可省略的
如上图,第一个 * 表示返回值类型是任意的,
第二个 * 表示包名,
第三个 .. 表示可以是多级包,
第四个ServiceImpl表示类名,
第五个 . * 表示指定类的所有方法
第六个 .. 表示方法的参数是任意的
举个例子:显示完整的方法名和切入点表达式
@Before("execution(* * ..ServiceImpl.*(..))")
public void after(JoinPoint jp){
System.out.println("前置通知切入点表达式:"+jp);
System.out.println("前置通知方法签名:"+jp.getSignature());
System.out.println("前置通知目标对象:"+jp.getTarget());
}
执行的结果:
前置通知切入点表达式:execution(int com.jnshu.IService.second(int))
前置通知方法签名:int com.jnshu.IService.second(int)
前置通知目标对象:com.jnshu.ServiceImpl@3bbc39f8
3、通知类型
所有通知类型都有JoinPoint参数
java.lang.Object[] getArgs():获取连接点方法运行时的入参列表;
Signature getSignature() :获取连接点的方法签名对象;
java.lang.Object getTarget() :获取连接点所在的目标对象;
java.lang.Object getThis() :获取代理对象本身;
@Before 前置通知
@AfterReturning 后置通知
可以添加result参数,用于显示返回值
@Around 环绕通知
环绕通知有方法的执行过程,所以必须有参数ProceedingJoinPoint,继承JoinPoint的子接口,环绕通知可以改变返回值结果,但是只有环绕通知的时候,虽然有 return result,但是不会将返回值result返回到控制台。
String name = pjp.getSignature().getName();
String name1 = pjp.getTarget().getClass().getName();
System.out.println("方法名;"+name+" "+"类名"+name1);
@AfterThrowing 异常通知
4、定义的切面
@Aspect
//指定当前类为切面
public class MyAspectj {
// 环绕通知
@Around("execution(* * ..ServiceImpl.*(..))")
public Object before(ProceedingJoinPoint pjp) throws Throwable {
long time1 = new Date().getTime();
System.out.println("环绕通知,方法执行前");
Object result = pjp.proceed();
if(result != null){
int r1 = (Integer) result + 10;
}
System.out.println("环绕通知,方法执行后");
long time2 = new Date().getTime();
System.out.println("执行方法用时:"+(time2-time1));
return result;
}
spring配置文件中内容
注册目标类,注册切面类,配置自动代理
<!--配置aspecctj的自动代理-->
<aop:aspectj-autoproxy/>
<!--注册目标类-->
<bean id="service" class="com.jnshu.ServiceImpl"/>
<!--注册切面类-->
<bean id="myAspectj" class="com.jnshu.MyAspectj"/>
二、xml式
spring配置文件中
<aop:before /> 表示前置方法
<!--xml式-->
<!--注册目标类-->
<bean id="service" class="com.jnshu.ServiceImpl"/>
<!--注册切面类--><bean id="aspectj2" class="com.jnshu.Aspectj2"/>
<!--配置AOP-->
<aop:config>
<!--定义切入点,可以是好几个-->
<aop:pointcut id="firstpoint1" expression="execution(* * ..ServiceImpl.first(..))"/>
<!--定义切面-->
<aop:aspect ref="aspectj2">
<!--前置通知-->
<aop:before method="before" pointcut-ref="firstpoint1"/>
</aop:aspect>
</aop:config>
两种方式都需要注册目标类和注册切面类
评论