1、使用Spring实现AOP简单切面编程
需要导入工程的jar包
Spring的核心包
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
Spring的测试包
spring-test-4.0.0.RELEASE.jar
Spring日记相关包
commons-logging-1.1.3.jar
log4j-1.2.17.jar
Spring的AOP切面相关的包
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
需要有的类
public interface Calculate {
public int add(int num1, int num2);
public int mul(int num1, int num2);
public int div(int num1, int num2);
public int sub(int num1, int num2);
}
@Component
public class Calculator implements Calculate {
@Override
public int add(int num1, int num2) {
return num1 + num2;
}
@Override
public int mul(int num1, int num2) {
return num1 * num2;
}
@Override
public int div(int num1, int num2) {
return num1 / num2;
}
@Override
public int sub(int num1, int num2) {
return num1 - num2;
}
}
@Aspect
@Component
public class LogUtil {
@Before(value = "execution(public int com.atguigu.aop.Calculator.add(int, int))")
public static void logBefore() {
System.out.println("前置 日记 :【xxx】 方法调用前 。参数1是:xxxx");
}
@After(value = "execution(public int com.atguigu.aop.Calculator.add(int, int))")
public static void logAfter() {
System.out.println("后置 日记 :【xxxx】 方法调用前 。参数1是:xxxx");
}
@AfterReturning(value = "execution(public int com.atguigu.aop.Calculator.add(int, int))")
public static void logAfterReturn() {
System.out.println("返回之后: 日记 :【xxxxx】 方法调用前 。参数1是:xxxxxx");
}
@AfterThrowing(value = "execution(public int com.atguigu.aop.Calculator.add(int, int))")
public static void logThrowException() {
System.out.println("抛异常:日记 :【xxxxx】 方法调用前 。参数1是:xxxxxx");
}
}
applicationContext.xml配置文件中的内容
<context:component-scan base-package="com.atguigu" />
<aop:aspectj-autoproxy />
测试代码
@ContextConfiguration(locations = "classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringAopTest {
@Autowired
private Calculate calculate;
@Test
public void test1() {
System.out.println( "添加:" + calculate.add(1, 2));
}
}
测试运行的结果
2、Spring的切入点表达式
@PointCut切入点表达式语法格式是: execution(访问权限 返回值类型 方法全限定名(参数类型列表))
限定符:
*:
1) 匹配某全类名下,任意或多个方法。
表示匹配com.atguigu.aop.Calculator下以a打头的任意方法。并且返回值和两个参数都是int类型。
execution(public int com.atguigu.aop.Calculator.a*(int, int))
表示匹配com.atguigu.aop.Calculator下的任意方法。并且返回值和两个参数都是int类型。
execution(public int com.atguigu.aop.Calculator.*(int, int))
2) 在Spring中只有public权限能拦截到,访问权限可以省略(访问权限不能写*)。
// 权限省略,表示任意类型的访问权限 ,但Spring现在只支持public权限
execution(int com.atguigu.aop.Calculator.*(int, int))
3) 匹配任意类型的返回值,可以使用 * 表示
// 表示任意类型的返回值
execution(* com.atguigu.aop.Calculator.*(int, int))
4) 匹配任意子包。
// 表示匹配com的子包
execution(* com.*.aop.Calculator.*(int, int))
5) 任意类型参数
// 表示第二个参数是任意类型
execution(* com.atguigu.aop.Calculator.*(int,*))
..:可以匹配多层路径,或任意多个任意类型参数
// 表示com和aop之间可以有任意层级的包
execution(* com..aop.Calculator.*(int,int))
// 表示第一个参数是int。之后可以有任意个任意类型的参数
execution(* com.atguigu.aop.Calculator.*(int,..))
模糊匹配:
// 表示任意返回值,任意方法全限定符,任意参数
execution(* *(..))
// 表示任意返回值,任意包名+任意方法名,任意参数
execution(* *.*(..))
精确匹配:
// int 返回值,com.atguigu.aop.Calculator类的add方法,两个int参数
execution(public int com.atguigu.aop.Calculator.add(int, int))
切入点表达式连接:&& 、||
// 表示需要同时满足两个表达式
@Before("execution(public int com.atguigu.aop.Calculator.add(int, int))"
+ " && "
+ "execution(public * com.atguigu.aop.Calculator.add(..))")
// 表示两个条件只需要满足一个,就会被匹配到
@Before("execution(public int com.atguigu.aop.Calculator.add(int, int))"
+ " || "
+ "execution(public * com.atguigu.aop.Calculator.a*(int))")
3、Spring切面中的代理对象
在Spring中,可以对有接口的对象和无接口的对象分别进行代理。在使用上有些细微的差别。
- 如果被代理的对象实现了接口。在获取对象的时候,必须要以接口来接收返回的对象。
测试的代码:
测试的结果:
- 被切面拦截的代理对象,如果没有实现接口。获取对象的时候使用对象类型本身
测试的代码:
测试结果