目录
1:什么是AspectJ的aop
AspectJ是一个基于java语言的(AOP)面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。spring2.0之后新增了对AspectJ的支持
需要导入sapectj的jar包
AspectJ支持Java注解和xml配置
@Before 前置通知,相当于BeforeAdvie(用于权限验证)
@AfterReturning 后置通知,相当于AfterReturningAdvie (操作日志记录)
@Around环绕通知,相当于MethodInterceptor(事务控制)
@AfterThrowing异常通知,相当于ThrowAdvie(用于权限验证)
@After 最终通知,无论是否异常都会通知,跟finally类似(用于权限验证)
定义切点:
execution(<访问修饰符> <返回值类型> <方法名>(<参数>)<异常>)
execution(public **(..))
2:怎么使用AspectJ的aop
2.1:基于AspectJ注解的方式实现AOP
目标类代码
package com.thit.aspectj1;
public class userdao {
public String add(){
System.out.println("添加方法!");
return "OMG!";
}
public void select(){
int i=0/0;
System.out.println("查询方法!");
}
public void update(){
System.out.println("修改方法!");
}
public String delete(){
System.out.println("删除方法!");
return "CNM";
}
}
切面类代码:
//作用是把当前类标识为一个切面供容器读取
@Component
@Aspect
public class aspectj {
// 前置通知
@Before("execution (* com.thit.aspectj1.userdao.ad*(..))")
public void before(JoinPoint j) {
System.out.println("前置通知" + j);
// 前置通知execution(void com.thit.aspectj1.userdao.add())
}
// 后置通知,returning定义方法返回值
@AfterReturning(value = "execution (* com.thit.aspectj1.userdao.add(..))", returning = "obj")
public void After(Object obj) {
System.out.println("后置通知");
System.out.println("后置通知接受方法参数:" + obj);
}
// 环绕通知,returning定义方法返回值
@Around(value = "execution (* com.thit.aspectj1.userdao.delete(..))")
public Object Around(ProceedingJoinPoint joinPoint) {
System.out.println("---环绕通知之前---");
Object o = null;
try {
// 如果没有joinPoint.proceed,则目标方法不会执行
o = joinPoint.proceed();
System.out.println("目标方法返回值:" + o);
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // 执行目标方法
System.out.println("---环绕通知之后---");
return o;
}
// 异常通知
@AfterThrowing(value = "execution (* com.thit.aspectj1.userdao.select(..))", throwing = "excption")
public void AfterThrowing(Throwable excption) {
System.out.println("---异常通知---:" + excption);
}
// 最终通知
@After(value = "execution (* com.thit.aspectj1.userdao.select(..))")
public void After() {
System.out.println("---最终无论是否有异常---");
}
}
切面代码类优化:
/**
*
* @author 79027 切面类
*/
@Aspect
public class aspectj {
// 前置通知
@Before("p1()")
public void before(JoinPoint j) {
System.out.println("前置通知" + j);
// 前置通知execution(void com.thit.aspectj1.userdao.add())
}
// 后置通知,returning定义方法返回值
@AfterReturning(value = "p2()", returning = "obj")
public void After(Object obj) {
System.out.println("后置通知");
System.out.println("后置通知接受方法参数:" + obj);
}
// 环绕通知,returning定义方法返回值
@Around(value = "p3()")
public Object Around(ProceedingJoinPoint joinPoint) {
System.out.println("---环绕通知之前---");
Object o = null;
try {
// 如果没有joinPoint.proceed,则目标方法不会执行
o = joinPoint.proceed();
System.out.println("目标方法返回值:" + o);
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // 执行目标方法
System.out.println("---环绕通知之后---");
return o;
}
// 异常通知
@AfterThrowing(value = "p4()", throwing = "excption")
public void AfterThrowing(Throwable excption) {
System.out.println("---异常通知---:" + excption);
}
// 最终通知
@After(value = "p5()")
public void After() {
System.out.println("---最终无论是否有异常---");
}
//用于隔离大量额切点配置,随着代码增加只需要更改这两部分即可,便于维护
@Pointcut("execution (* com.thit.aspectj1.userdao.ad*(..))")
private void p1() {};
@Pointcut(value = "execution (* com.thit.aspectj1.userdao.add(..))")
private void p2() {};
@Pointcut(value = "execution (* com.thit.aspectj1.userdao.delete(..))")
private void p3() {};
@Pointcut(value = "execution (* com.thit.aspectj1.userdao.delete(..))")
private void p4() {};
@Pointcut(value = "execution (* com.thit.aspectj1.userdao.select(..))")
private void p5() {};
}
xml配置文件
<!--开启aspectJ的自动注解 否则不会成效
等效为注解 @EnableAspectJAutoProxy 加了这个注解 就不用使用配置了-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!--目标类 -->
<bean id="userdao" class="com.thit.aspectj1.userdao"></bean>
<!--切面类-->
<bean class="com.thit.aspectj1.aspectj"></bean>
测试方法:
public void test1() {
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
userdao u=(userdao) context.getBean("userdao");
u.add();
System.out.println("----------------------------------------------");
u.delete();
System.out.println("----------------------------------------------");
u.update();
System.out.println("----------------------------------------------");
u.select();
}
输出结果:
----------------------------------------------
前置通知execution(String com.thit.aspectj1.userdao.add())
添加方法!
后置通知
后置通知接受方法参数:OMG!
----------------------------------------------
---环绕通知之前---
删除方法!
目标方法返回值:CNM
---环绕通知之后---
----------------------------------------------
修改方法!
----------------------------------------------
---最终无论是否有异常---
---异常通知---:java.lang.ArithmeticException: / by zero
2.2:基于配置实现AspectJ的AOP
目标类代码
package com.thit.aspectj2xml;
public class userdao {
public String add(){
System.out.println("添加方法!");
return "OMG!";
}
public void select(){
int i=0/0;
System.out.println("查询方法!");
}
public void update(){
System.out.println("修改方法!");
}
public String delete(){
System.out.println("删除方法!");
return "CNM";
}
}
切面类代码:
package com.thit.aspectj2xml;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.After;
/**
*
* @author 79027 切面类
*/
@Aspect
public class aspectj {
// 前置通知
public void before(JoinPoint j) {
System.out.println("前置通知" + j);
// 前置通知execution(void com.thit.aspectj1.userdao.add())
}
// 后置通知,returning定义方法返回值
public void Afterreturning(Object return1) {
System.out.println("后置通知");
System.out.println("后置通知接受方法参数:" + return1);
}
// 环绕通知,returning定义方法返回值
public Object Around(ProceedingJoinPoint joinPoint) {
System.out.println("---环绕通知之前---");
Object o = null;
try {
// 如果没有joinPoint.proceed,则目标方法不会执行
o = joinPoint.proceed();
System.out.println("目标方法返回值:" + o);
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // 执行目标方法
System.out.println("---环绕通知之后---");
return o;
}
// 异常通知
public void AfterThrowing1(Throwable excption) {
System.out.println("---异常通知---:" + excption);
}
// 最终通知
public void After() {
System.out.println("---最终无论是否有异常都会执行---");
}
}
xml配置文件
<!--目标类 -->
<bean id="userdao" class="com.thit.aspectj2xml.userdao"></bean>
<!--切面类 -->
<bean id="aspectj" class="com.thit.aspectj2xml.aspectj"></bean>
<!-- AOP配置 -->
<aop:config>
<!--配置切入点 execution (* com.thit.aspectj1.userdao.ad*(..)) -->
<aop:pointcut expression="execution (* com.thit.aspectj2xml.userdao.add(..))" id="pointcut1" />
<aop:pointcut expression="execution (* com.thit.aspectj2xml.userdao.ad*(..))" id="pointcut2" />
<aop:pointcut expression="execution (* com.thit.aspectj2xml.userdao.delete(..))" id="pointcut3" />
<aop:pointcut expression="execution (* com.thit.aspectj2xml.userdao.sel*(..))" id="pointcut4" />
<aop:pointcut expression="execution (* com.thit.aspectj2xml.userdao.sel*(..))" id="pointcut5" />
<!--配置切面 -->
<aop:aspect ref="aspectj">
<aop:before method="before" pointcut-ref="pointcut1"/>
<aop:after-returning method="Afterreturning" pointcut-ref="pointcut2" returning="return1"/>
<aop:around method="Around" pointcut-ref="pointcut3" />
<aop:after-throwing method="AfterThrowing1" pointcut-ref="pointcut4" throwing = "excption"/>
<aop:after method="After" pointcut-ref="pointcut4"/>
</aop:aspect>
</aop:config>
执行结果:
----------------------------------------------
前置通知execution(String com.thit.aspectj2xml.userdao.add())
添加方法!
后置通知
后置通知接受方法参数:OMG!
----------------------------------------------
---环绕通知之前---
删除方法!
目标方法返回值:CNM
---环绕通知之后---
----------------------------------------------
修改方法!
----------------------------------------------
---最终无论是否有异常都会执行---
---异常通知---:java.lang.ArithmeticException: / by zero