spring中提供了两种方法实现AOP,Schema-base和AspectJ。
该方法要求每个通知继承相应的类或实现相应的接口。然后配置applicationContext.xml中的aop:config标签。
这里在同一个包下定义两个类,包含了多种方法,用于配置不同的切点。
public class Demo {
public void function1() {
System.out.println("pointcut-Demo.function1");
}
public void function2() throws Exception{
int x = 5 / 0; //用于抛出异常
System.out.println("pointcut-Demo.function2");
}
public void function3() {
System.out.println("pointcut-Demo.function3");
}
}
public class Demo2 {
public boolean function1(String message, int num) {
System.out.println("pointcut-Demo2.function1");
if (num > 10) {
return true;
}
return false;
}
}
public class MyBeforeAdvice implements MethodBeforeAdvice {
/**
* @param method 切点方法对象
* @param objects 切点方法参数列表
* @param o 切点所在类的对象
*/
@Override
public void before(Method method, Object[] objects, Object o) {
System.out.println("前置通知");
}
}
public class MyAfterAdvice implements AfterReturningAdvice {
/**
* @param o 切点方法返回值
* @param method 切点方法对象
* @param objects 切点方法参数列表
* @param o1 切点所在类的对象
*/
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) {
System.out.println("后置通知");
}
}
public class MyThrowingAdvice implements ThrowsAdvice {
public void afterThrowing(Exception ex) throws Throwable {
System.out.println("执行异常通知:异常-》" + ex.getMessage() + " schema-base方式");
}
}
public class MyAroundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("环绕-前置通知");
Object result = methodInvocation.proceed(); //执行切点中的内容
System.out.println("环绕-后置通知");
return result;
}
}
<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.xsd">
<bean id="demo" class="com.bear.sxt.pointcut.Demo"/>
<bean id="demo2" class="com.bear.sxt.pointcut.Demo2"/>
<bean id="myBeforeAdvice" class="com.bear.sxt.advice.MyBeforeAdvice"/>
<bean id="myAfterAdvice" class="com.bear.sxt.advice.MyAfterAdvice"/>
<bean id="myThrows" class="com.bear.sxt.advice.MyThrowingAdvice"/>
<bean id="myAroundAdvice" class="com.bear.sxt.advice.MyAroundAdvice"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.bear.sxt.pointcut.*.function1(..))"/>
<aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="myAfterAdvice" pointcut-ref="pointcut"/>
aop:config>
<aop:config>
<aop:pointcut id="pointcutThrows" expression="execution(* com.bear.sxt.pointcut.Demo.function2())"/>
<aop:advisor advice-ref="myThrows" pointcut-ref="pointcutThrows"/>
aop:config>
<aop:config>
<aop:pointcut id="pointcutAround" expression="execution(* com.bear.sxt.pointcut.Demo.function3())"/>
<aop:advisor advice-ref="myAroundAdvice" pointcut-ref="pointcutAround"/>
aop:config>
beans>
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Demo demo = ac.getBean("demo", Demo.class);
Demo2 demo2 = ac.getBean("demo2", Demo2.class);
/*使用schema-base方式*/
System.out.println("schema-base方式");
System.out.println("----------》不带参数的切点");
demo.function1();
System.out.println("----------》带参数的切点");
demo2.function1("hello", 20);
System.out.println("----------》带异常的切点");
try {
demo.function2();
} catch (Exception e) {
//e.printStackTrace();
}
System.out.println("----------》带环绕通知的切点");
demo.function3();
}
}
该方法不要求每个通知继承相应的类或实现相应的接口,只需要配置applicationContext.xml中的aop:config标签中的aop:aspect子标签即可。最终实现的效果和schema-base方式是一样的。
这里用到的切点类有两个带参数和返回值的方法。
public class DemoAspectJ {
public Object function(String message,int num) {
if (0 != num) {
System.out.println("pointcut-DemoAspectJ.function message:" + message);
return true;
} else {
int x = 5 / 0;
}
return false;
}
public Object function2(String message,int num) {
System.out.println("pointcut-DemoAspectJ.function message:" + message);
return 0;
}
}
由于采用aspectJ方式,通知无需继承相应的类和实现相应的接口,所以每一个通知操作可以写成一个方法,多种通知可以写在同一个类中。
public class MyAdvice {
public void myBefore() {
System.out.println("前置通知");
}
/*message,num为切点参数*/
public void myBefore2(String message, int num) {
System.out.println("前置通知 " + message + " " + num);
}
public void myAfter() {
System.out.println("后置通知-出现异常继续执行");
}
public void myAfterReturning() {
System.out.println("后置通知-出现异常不执行");
}
public void myThrows(Exception e) {
System.out.println("执行异常通知:" + e.getMessage() + " aspectJ方式");
}
public void myAround(ProceedingJoinPoint p) throws Throwable {
System.out.println("环绕-前置");
Object result = p.proceed();
System.out.println("环绕-后置");
}
}
<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.xsd">
<bean id="demoAspectJ" class="com.bear.sxt.pointcut.DemoAspectJ"/>
<bean id="myAdvice" class="com.bear.sxt.advice.MyAdvice"/>
<aop:config>
<aop:aspect ref="myAdvice">
<aop:pointcut id="pointcut2" expression="execution(* com.bear.sxt.pointcut.DemoAspectJ.function(..))"/>
<aop:around method="myAround" pointcut-ref="pointcut2"/>
<aop:before method="myBefore" pointcut-ref="pointcut2"/>
<aop:after method="myAfter" pointcut-ref="pointcut2"/>
<aop:after-returning method="myAfterReturning" pointcut-ref="pointcut2"/>
<aop:after-throwing method="myThrows" pointcut-ref="pointcut2" throwing="e"/>
aop:aspect>
<aop:aspect ref="myAdvice">
<aop:pointcut id="pointcut3" expression="execution(* com.bear.sxt.pointcut.DemoAspectJ.function2(String,int)) and args(message,num)"/>
<aop:before method="myBefore2" pointcut-ref="pointcut3" arg-names="message,num"/>
aop:aspect>
aop:config>
beans>
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
DemoAspectJ demoAspectJ = ac.getBean("demoAspectJ", DemoAspectJ.class);
/*使用AspectJ方式*/
System.out.println("aspectJ方式");
System.out.println("----------》不传递参数的通知");
demoAspectJ.function("张三", 10);
System.out.println("----------》传递参数的通知");
demoAspectJ.function2("李四", 20);
}
}