1 AspectJ:面向切面的框架,定义了AOP语法,有一个专门的编译器用来生成遵守Java字节码规范的class文件
2 AspectJ 的通知类型
常用的有五种
前置通知,后置通知,环绕通知,异常通知,
最终通知(无论程序是否运行正常必执行,类似于try catch中的finally代码块)
3 切入点表达式
定义了专门的表达式用于指定切入点,表达式原型
execution ( [modifiers-pattern] 访问权限类型
ret-type-pattern 返回值类型
[declaring-type-pattern] 全限定性类名
name-pattern(param-pattern) 方法名(参数名)
[throws-pattern] 抛出异常类型
)
举例
execution (public * * {..})
指定切入点为任意 公共 方法
execution (* set * {..})
指定切入点为任何一个以“set”开始的方法
execution (* com.cj.service.* .* {..})
指定切入点为service包里的任意类的任意方法
execution (* com.cj.service..* .* {..})
指定切入点为service包及其子包里的任意类的任意方法,“..”出现在类名中时后必须跟“*”,表示包和子包下的所有类
execution (* com.cj.service.IService .* {..})
IService 接口中的任意方法
execution (* com.cj.service.IService+ .* {..})
IService若为接口,则为IService 接口中的任意方法及其实现类的方法;若为类,则为该类及其子类任意方法
execution (* hello(String,int))
所有hello(String,int)方法,非lang包下的类作为参数需写全限定类名,例如hello(java.util.List,int)
execution (* hello(String,*))
所有hello(String,*)方法,参数支持通配符
4 AspectJ的开发环境
需要AOP环境+com.springsource.org.aspectj.weaver.jar (+com.springsource.org.aspectj.tools.jar)
AOP环境,引入AOP约束
5 AspectJ 基于注解的AOP实现 前置通知
(1)实现步骤
step1:定义业务接口和实现类
public interface IUserService{
//主业务方法
void doSome();
//主业务方法
void doOther(int a,String b);
//主业务方法
String doThird();
}
step2 :定义切面POJO类
step3:在切面上添加@Aspect注解
@Aspect //表示当前POJO类为切面
public class MyAspect{//POJO类
@Before("execution(* *..IUserService.doSome(..))") //用(..)可支持有参与无参方法,更好
public void myBefore(){
System.out.println("执行前置通知方法");
}
@Before("execution(* *..IUserService.doThird(..))") //用(..)可支持有参与无参方法,更好
public void myBefore(JoinPoint jp){
System.out.println("执行前置通知方法===+jp;"+jp);//JoinPoint为切入点表达式
}
}
step4:在POJO类的普通方法上添加注解
step5:注册目标对象与POJO类
目标对象
<bean id="userService" class="com.cj.service.UserServiceImpl"/>
切面
<bean id="myAspect" class="com.cj.aspect.MyAspect"/>
step6:注册AspectJ的自动代理
AspectJ的自动代理
<aop:aspectj-autoproxy/>
step7:测试类中使用目标对象的id
@Test
public void test01(){
//创建容器
String resource = "applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
IUserService userService = (IUserService) ac.getBean("userService");
service.doSome();
}
后置通知
@AfterReturning("execution(* *..IUserService.doSecond(..))")
public void myAfter(JoinPoint jp){
System.out.println("执行后置通知方法===+jp;"+jp);//JoinPoint为切入点表达式
}
@AfterReturning(value="execution(* *..IUserService.doThird(..))",returning="result") //doThird有返回值
public void myAfter(Object result){
System.out.println("执行后置通知方法===+result;"+result);//JoinPoint为切入点表达式
}
环绕通知
@Around("execution(* *..IUserService.doSecond(..))")
public Object myAroundr(ProceedJoinPoint pjp) throws Throwable{
System.out.println("执行环绕通知方法之前===+pjp;"+pjp);
Object result = pjp.proceed();
System.out.println("执行环绕通知方法之后===+pjp;"+pjp);
return result;
}
异常通知
@AfterThrowing("execution(* *..IUserService.doSecond(..))")
public void myAfterThrowing(){//监控指定目标方法执行是否发生异常
System.out.println("执行异常通知方法===+");//JoinPoint为切入点表达式
}
@AfterThrowing(value="execution(* *..IUserService.doSecond(..))",throwing="ex")
public void myAfterThrowing(Exception ex){//监控指定目标方法执行是否发生异常
System.out.println("执行异常通知方法===+ex::::"ex.getMessage());/打印异常信息
}
最终通知
@After("execution(* *..IUserService.doSome(..))")
public void myAfter(){
System.out.println("执行最终通知方法myAfter();");//最终通知在后置前执行
}
定义切入点(切入点冗余)
@Pointcut("execution(* *..IUserService.doSome(..))")
private void doSomePointcut(){}
@After("doSomePointcut()")
public void myAfter(){
System.out.println("执行最终通知方法myAfter();");//最终通知在后置前执行
}
6 AspectJ 基于xml的AOP实现 (常用)
前置通知
//POJO类,定义切面
public class MyAspect{
public void myBefore(){
System.out.println("执行前置通知方法");
}
public void myBefore(){
System.out.println("执行前置通知方法===");
}
}
目标对象
<bean id="userService" class="com.cj.service.UserServiceImpl"/>
切面
<bean id="myAspect" class="com.cj.aspect.MyAspect"/>
AOP配置
<aop:config>
(aspect,pointcut,advisor)
<aop:pointcut expression="execution()" id="doSomePointCut"/>
<aop:aspect ref="myAspect">
<aop:before method="myBefore" point-ref="doSomePointCut"/>
<aop:before method="myBefore(全限定参数名例如org.aspect.lang.JoinPoint)" point-ref="doSomePointCut"/>
</aop:aspect>
</aop:config>
其他通知与其类似,名称参数与注解类似