鲁春利的工作笔记,好记性不如烂笔头
基于XML配置方式声明切面
Spring使用org.springframework.aop.Advisor接口表示切面的概念,Advisor表示只有一个通知(org.aopalliance.aop.Advice)和一个切入点(org.springframework.aop.Pointcut)的切面。Advisor可以使用<aop:config>标签下的<aop:advisor>标签定义。
<aop:advisor id="标识" order="执行顺序" pointcut="切入点表达式" pointcut-ref="切入点Bean引用" advice-ref="通知API实现引用" />
pointcut和pointcut-ref:二者选一,指定切入点表达式;
advice-ref:引用通知API实现Bean,如前置通知接口为MethodBeforeAdvice;
Spring配置文件(spring-context-aop-advisor.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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 业务类 --> <bean id="calculate" class="com.invicme.apps.aop.advisor.ArithmeticCalculateImpl" /> <!-- 切入的日志类 --> <bean id="beforeAdviceLogAdapter" class="com.invicme.apps.aop.advisor.BeforeAdviceLogAdapter" /> <bean id="afterAdviceLogAdapter" class="com.invicme.apps.aop.advisor.AfterReturningAdviceLogAdapter" /> <bean id="throwAdviceLogAdapter" class="com.invicme.apps.aop.advisor.ThrowAdviceLogAdapter" /> <bean id="aroundAdviceLogAdapter" class="com.invicme.apps.aop.advisor.AroundInterceptorLogAdapter" /> <!-- proxy-target-class true : 表示声明的切面使用CGLib动态代理技术; false : 默认值,使用JDK动态代理技术。 一个配置文件可以有多个<aop:config>,不同的<aop:config>采用不同的代理技术。 --> <aop:config proxy-target-class="false"> <!-- 声明一个切点 --> <aop:pointcut id="logPointcut" expression="execution(public * com.invicme.apps.aop.advisor.ArithmeticCalculateImpl.*(..))"/> <!-- advisor只持有一个Pointcut和一个advice,而aspect可以多个pointcut和多个advice --> <aop:advisor advice-ref="beforeAdviceLogAdapter" pointcut-ref="logPointcut" /> <aop:advisor advice-ref="afterAdviceLogAdapter" pointcut-ref="logPointcut" /> <aop:advisor advice-ref="throwAdviceLogAdapter" pointcut-ref="logPointcut"/> <aop:advisor advice-ref="aroundAdviceLogAdapter" pointcut-ref="logPointcut"/> </aop:config> </beans>
实现类
package com.invicme.apps.aop.advisor;
import org.apache.log4j.Logger;
import com.invicme.apps.aop.ArithmeticCalculate;
/**
*
* @author lucl
*
* 数学计算实现类
*
*/
public class ArithmeticCalculateImpl implements ArithmeticCalculate {
private static final Logger logger = Logger.getLogger(ArithmeticCalculateImpl.class);
private int i = 0;
private int j = 0;
public ArithmeticCalculateImpl () {
this(0, 0);
}
public ArithmeticCalculateImpl (int i, int j) {
this.i = i;
this.j = j;
}
@Override
public int add(int i, int j) {
logger.info("The method add was invoke with args [" + i + ", " + j + "]");
int sum = i + j;
logger.info("The method add ends with result [" + sum + "]");
return sum;
}
@Override
public int div(int i, int j) {
logger.info("The method div was invoke with args [" + i + ", " + j + "]");
int result = i / j;
logger.info("The method div ends with result [" + result + "]");
return result;
}
@Override
public String validateNum(String level, int i) {
logger.info("The method validateNum was invoke with args [" + level + ", " + i + "]");
String result = this.getMsg(i);
logger.info("The method validateNum ends with result [" + result + "]");
return result;
}
private String getMsg (int i) {
if (i > 0) {
return "正数";
}
return "负数";
}
}
前置通知
package com.invicme.apps.aop.advisor;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.apache.log4j.Logger;
import org.springframework.aop.MethodBeforeAdvice;
/**
*
* @author lucl
*
* 前置通知(Adivisor是一种特殊的Aspect,Advisor代表spring中的Aspect )
*
*/
public class BeforeAdviceLogAdapter implements MethodBeforeAdvice {
private static final Logger logger = Logger.getLogger(BeforeAdviceLogAdapter.class);
/**
* 前置通知,在目标方法执行之前被调用(JoinPoint参数不是必须的,传入是为了获取目标对象的相关属性)
*/
public void before(Method method, Object[] args, Object target) throws Throwable {
/**
* target.getClass().getName() : 获取的是全路径名(包名+类名)
* target.getClass().getSimpleName() : 获取类名
*/
String className = target.getClass().getSimpleName();
logger.info("[<aop:before>]" + className + "@" + method.getName() + " was invoke with args " + Arrays.asList(args) + ".");
}
}
后置通知
package com.invicme.apps.aop.advisor;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.apache.log4j.Logger;
import org.springframework.aop.AfterReturningAdvice;
/**
*
* @author lucl
*
* 后置通知
*/
public class AfterReturningAdviceLogAdapter implements AfterReturningAdvice {
private static final Logger logger = Logger.getLogger(AfterReturningAdviceLogAdapter.class);
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
String className = target.getClass().getSimpleName();
logger.info("[<aop:after-returning>]" + className + "@" + method.getName() + " args " + Arrays.asList(args) + ", result " + returnValue + ".");
}
}
异常通知
package com.invicme.apps.aop.advisor;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.apache.log4j.Logger;
import org.springframework.aop.ThrowsAdvice;
/**
*
* @author lucl
*
* 异常通知
*
* <pre>
* There are not any methods on this interface, as methods are invoked by reflection.
* Implementing classes must implement methods of the form:
*
* void afterThrowing([Method, args, target], ThrowableSubclass);
* Some examples of valid methods would be:
*
* public void afterThrowing(Exception ex)
* public void afterThrowing(RemoteException)
* public void afterThrowing(Method method, Object[] args, Object target, Exception ex)
* public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)
* </pre>
*/
public class ThrowAdviceLogAdapter implements ThrowsAdvice {
private static final Logger logger = Logger.getLogger(ThrowAdviceLogAdapter.class);
/**
*
* @param method
* @param args
* @param target
* @param ex
*/
public void afterThrowing(Method method, Object[] args, Object target, Exception ex) {
String className = target.getClass().getSimpleName();
logger.info("[<aop:after-throwing>]" + className + "@" + method.getName() + " args " + Arrays.asList(args) + " occurs exception : " + ex + ".");
}
}
环绕通知
package com.invicme.apps.aop.advisor;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.log4j.Logger;
/**
*
* @author 环绕通知
*
*/
public class AroundInterceptorLogAdapter implements MethodInterceptor {
private static final Logger logger = Logger.getLogger(AroundInterceptorLogAdapter.class);
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// 参数
Object [] args = invocation.getArguments();
// 目标方法
Method method = invocation.getMethod();
Object result = null;
try {
// before advise
logger.info("[<aop:aroud>]" + method.getName() + " was invoke with args " + Arrays.asList(args) + ".");
result = invocation.proceed();
} catch (Exception ex) {
// throw advise
logger.info("[<aop:aroud>]" + method.getName() + " occrus error " + ex + ".");
}
// after running advise
logger.info("[<aop:aroud>]" + method.getName() + " ends with result " + result + ".");
return result;
}
}
单元测试类
package com.test.apps.spring.aop;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.invicme.apps.aop.ArithmeticCalculate;
/**
*
* @author lucl
*
*/
public class TestSpringAopOfAdvisor {
@Test
public void testSpringAopOfAdvisor () {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring/spring-context-aop-advisor.xml");
ArithmeticCalculate calculate = context.getBean("calculate", ArithmeticCalculate.class);
calculate.add(1, 2);
System.out.println("----------------------------------------------------------------");
try {
Thread.sleep(1 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
calculate.div(1, 0);
}
}
执行结果
不推荐使用Advisor,除非在进行事务控制的情况下,其他情况一般不推荐使用该方式,该方式属于侵入式设计,必须实现通知API。
转载于:https://blog.51cto.com/luchunli/1826092