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 {@Overridepublic int add(int num1, int num2) {return num1 + num2;}@Overridepublic int mul(int num1, int num2) {return num1 * num2;}@Overridepublic int div(int num1, int num2) {return num1 / num2;}@Overridepublic 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 {@Autowiredprivate Calculate calculate;@Testpublic 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中,可以对有接口的对象和无接口的对象分别进行代理。在使用上有些细微的差别。
- 如果被代理的对象实现了接口。在获取对象的时候,必须要以接口来接收返回的对象。
测试的代码:
测试的结果:
- 被切面拦截的代理对象,如果没有实现接口。获取对象的时候使用对象类型本身
测试的代码:
测试结果