AspectJ——基于注解的声明式AspectJ
1.AspectJ注解的介绍
@Aspect: 用于定义一个切面
@Pointcut: 用于定义切入点的表达式。在使用时还需要定义一个包含名字和任意参数的方法签名来表示切入点名称。实际上,这个方法签名就是一个返回值void,且方法体为空的普通方法
@Before: 用于定义前置通知,在使用时需要指定一个value属性值,该属性值用于指定一个切入点表达式。
@AfterReturning: 用于定义后置通知,在使用时可以指定pointcut/value和retruning属性,其中pointcut/value这两个属性作用是一样的,都用于指定切入点表达式。returning属性值用于标识Advice方法中可定义与此同名的形参,该形参可用于访问目标方法的返回值。
@Around: 用于定义环绕通知,相当于MethodInterceptor.在使用时需要指定一个value属性,该属性用于指定该通知被植入的切入点。
2.练习
(1)项目的src下创建com.items.aspectj.annotation包,并创建接口,接口的实现类,切面类,xml文件,测试类。
(2)接口UserDao.java
package com.items.aspectj;
public interface UserDao {
public void hello();
public void hello2();
}
(3)接口实现类UserDaoIml.java
package com.items.aspectj;
public class UserDaoIml implements UserDao{
@Override
public void hello() {
System.out.println("运行中1。。。");
}
@Override
public void hello2() {
System.out.println("运行中2。。。");
}
public static void main(String [] args){
UserDao userDao = new UserDaoIml();
userDao.hello();
}
}
(3)切面类MyAspect.java
package com.items.aspectj;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
/*
* 切面类,在此类中编写通知
*/
public class MyAspect {
//前置通知
public void myBefore(JoinPoint joinPoint) {
System.out.println("前置通知:模拟执行权限。。。。");
System.out.println("目标类是:" + joinPoint.getTarget());
System.out.println("被增强的目标类的方法是" + joinPoint.getSignature().getName());
}
//后置通知
public void myAfterReturn(JoinPoint joinPoint) {
System.out.println("后置通知:模拟日志记录....");
System.out.println("被增强的目标类的方法是" + joinPoint.getSignature().getName());
}
/*
* 环绕通知
* ProceedingJoinPoint是JoinPoint的子接口
* 必须是Object的返回值
* 必须接收一个参数类型为ProceedingJoinPoint
* 必须throws Throwable
*/
public Object myAroud(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕开始:模拟开启事务...");
//执行当前目标方法
Object obj = proceedingJoinPoint.proceed();
System.out.println("环绕结束:模拟关闭事务...");
return obj;
}
//异常通知
public void myAfterThrows(JoinPoint joinPoint, Throwable e){
System.out.println("异常通知:" + "出错了:" + e.getMessage());
}
//最终通知
public void myAfter(){
System.out.println("最终通知:模拟方法结束释放资源");
}
}
(4) aplicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
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-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
xmlns:context="http://www.springframework.org/schema/context"> <!-- bean definitions here -->
<!-- 指定需要扫描的 包,使注解生效 -->
<context:component-scan base-package="com.items.aspectj.annotation"/>
<!-- 启动基于注解的声明式AspectJ支持 -->
<aop:aspectj-autoproxy/>
</beans>
(5) 测试类AspectTest.java
package com.items.aspectj.annotation;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AspectTest {
public static void main(String [] args) {
String xmlPath = "com/items/aspectj/annotation/aplicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
userDao.hello();
}
}
之前遇到错误:通配符的匹配很全面, 但无法找到元素 'context:component-scan' 的声明。
错误原因是aplicationContext.xml中xsi:schemaLocation中配置没对
学习书籍:《javaEE企业级应用开发程序》