- 基于配置文件的切面配置,废话不多说,上代码
- 涉及到的配置文件aop.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.xsd">
<!--配置aop切面,先注入切面类和被代理对象的类-->
<bean id="sucurityUtil" class="my.utils.SucurityUtil"></bean>
<bean id="logUtil" class="my.utils.LogUtil"></bean>
<bean id="calculatorImpl" class="my.reflect.CalculatorImpl"></bean>
<aop:config>
<!--如果pointcut相同,可以抽象出公用的,每个消息通知中可以使用pointcut-ref引用-->
<aop:pointcut id="globalpointcut" expression="execution(public Integer my.reflect.CalculatorImpl.*(..))"></aop:pointcut>
<aop:aspect ref="sucurityUtil" order="1">
<aop:before method="methodStartLog" pointcut-ref="globalpointcut" ></aop:before>
<aop:after-returning method="methodStopLog" pointcut-ref="globalpointcut" returning="result"></aop:after-returning>
<aop:after-throwing method="methodExceptionLog" pointcut-ref="globalpointcut" throwing="e"></aop:after-throwing>
<aop:after method="methodFinallyLog" pointcut-ref="globalpointcut"></aop:after>
</aop:aspect>
<aop:aspect ref="logUtil" order="2">
<aop:before method="methodStartLog" pointcut="execution(public Integer my.reflect.CalculatorImpl.*(..))" ></aop:before>
<aop:after-returning method="methodStopLog" pointcut="execution(public Integer my.reflect.CalculatorImpl.*(..))" returning="result"></aop:after-returning>
<aop:after-throwing method="methodExceptionLog" pointcut="execution(public Integer my.reflect.CalculatorImpl.*(..))" throwing="e"></aop:after-throwing>
<aop:after method="methodFinallyLog" pointcut="execution(public Integer my.reflect.CalculatorImpl.*(..))"></aop:after>
</aop:aspect>
</aop:config>
</beans>
package my.utils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.Arrays;
//@Aspect
//@Component
//@Order注解可以限定多个切面的执行顺序,例如本案例中的(LogUtil和SecurityUtil)两个切面类,设置order注解的value属性,数值越小先执行,
//如果两个都没有设置order,默认是按照切面类名字典排序
//@Order(value = 1)
public class SucurityUtil {
@Before(value = "myPointCut()")
public static void methodStartLog(JoinPoint joinPoint){
System.out.println("Security-->"+joinPoint.getSignature().getName()+"方法开始执行,参数为:"+ Arrays.asList(joinPoint.getArgs()));
}
@AfterReturning(value = "execution(public Integer my.reflect.CalculatorImpl.*(Integer,Integer))",returning = "result")
public static void methodStopLog(JoinPoint joinPoint,Object result){
System.out.println("Security-->"+joinPoint.getSignature().getName()+"方法执行完毕,结果为:"+result);
}
@AfterThrowing(value = "execution(public Integer my.reflect.CalculatorImpl.*(Integer,Integer))",throwing = "e")
public static void methodExceptionLog(JoinPoint joinPoint,Exception e){
System.out.println("Security-->"+joinPoint.getSignature().getName()+"方法出现异常:"+e.getMessage());
}
@After(value = "execution(public Integer my.reflect.CalculatorImpl.*(Integer,Integer))")
public static void methodFinallyLog(JoinPoint joinPoint){
System.out.println("Security-->"+joinPoint.getSignature().getName()+"方法最终输出结果");
}
//定义pointCut 如果多个方法的切点表达式一致,就可以把切点表达式抽象出来:
// 定义一个没有返回值的空方法,给该方法添加@PointCut方法,后续在使用的时候可以直接调用方法名称
@Pointcut(value = "execution(public Integer my.reflect.CalculatorImpl.*(Integer,Integer))")
public void myPointCut(){ }
}
package my.utils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* 通知注解有以下几种类型
* @Before 前置通知,在指定方法执行之前执行
* @After 后置通知,在指定方法执行之后执行
* @AferReturning 返回通知,在返回结果之后执行
* @AfterThrowing 异常通知,出现异常的时候使用
* @Around 环绕通知
*
* 注意:在每个通知方法(add,sub,mul,div)中,不要随便添加参数值,会有异常信息
*/
//@Aspect //声明当前类是一个切面类
//@Component //将切面类实例添加到ioc容器中
//@Order(value = 2)
public class LogUtil {
@Before(value = "myPointCut()")
public static void methodStartLog(JoinPoint joinPoint){
System.out.println(joinPoint.getSignature().getName()+"方法开始执行,参数为-----:"+ Arrays.asList(joinPoint.getArgs()));
}
@AfterReturning(value = "execution(public Integer my.reflect.CalculatorImpl.*(Integer,Integer))",returning = "result")
public static void methodStopLog(JoinPoint joinPoint,Object result){
System.out.println(joinPoint.getSignature().getName()+"方法执行完毕,结果为-----:"+result);
}
@AfterThrowing(value = "execution(public Integer my.reflect.CalculatorImpl.*(Integer,Integer))",throwing = "e")
public static void methodExceptionLog(JoinPoint joinPoint,Exception e){
System.out.println(joinPoint.getSignature().getName()+"方法出现异常-----:"+e.getMessage());
}
@After(value = "execution(public Integer my.reflect.CalculatorImpl.*(Integer,Integer))")
public static void methodFinallyLog(JoinPoint joinPoint){
System.out.println(joinPoint.getSignature().getName()+"方法最终输出结果-----");
}
//定义pointCut 如果多个方法的切点表达式一致,就可以把切点表达式抽象出来:
// 定义一个没有返回值的空方法,给该方法添加@PointCut方法,后续在使用的时候可以直接调用方法名称
@Pointcut(value = "execution(public Integer my.reflect.CalculatorImpl.*(Integer,Integer))")
public void myPointCut(){ }
//如果要修改方法执行后的返回值,就只能用环绕通知,只有环绕通知可以修改当前执行方法的返回值
/* @Around(value = "myPointCut()")
public Object around(ProceedingJoinPoint proceedingJoinPoint){
Signature signature = proceedingJoinPoint.getSignature();
Object[] args = proceedingJoinPoint.getArgs();
Object obj = null;
try {
System.out.println("环绕通知start-->"+signature.getName()+"方法开始执行,参数列表是:"+Arrays.asList(args));
obj= proceedingJoinPoint.proceed();
System.out.println("环绕通知stop-->"+signature.getName()+"方法执行结束");
} catch (Throwable throwable) {
System.out.println("环绕通知异常-->"+signature.getName()+"方法出现异常:"+throwable.getMessage());
throwable.printStackTrace();
}finally {
System.out.println("环绕返回通知-->"+signature.getName()+"方法返回结果是:"+obj);
}
return obj;
}*/
}
package my.reflect;
import org.springframework.stereotype.Component;
public interface Calculator {
Integer add(Integer x, Integer y) throws NoSuchMethodException;
Integer sub(Integer x, Integer y) throws NoSuchMethodException;
Integer mul(Integer x, Integer y) throws NoSuchMethodException;
Integer div(Integer x, Integer y) throws NoSuchMethodException;
}
package my.reflect;
import org.springframework.stereotype.Component;
//被代理的类添加到IOC容器中,保证ioc容器能扫描到
//@Component //此处的注解可以替代aop.xml中的bean标签中注册的类
public class CalculatorImpl
//此处是否实现父接口是决定aop采用何种方式的动态代理的关键,如果实现了父接口,那几采用jdk的
implements Calculator
{
@Override
public Integer add(Integer x, Integer y) throws NoSuchMethodException {
int result = x + y;
return result;
}
@Override
public Integer sub(Integer x, Integer y) throws NoSuchMethodException {
int result = x - y;
return result;
}
@Override
public Integer mul(Integer x, Integer y) throws NoSuchMethodException {
int result = x * y;
return result;
}
@Override
public Integer div(Integer x, Integer y) throws NoSuchMethodException {
int result = x / y;
return result;
}
}
@Test
public void test02() throws NoSuchMethodException {
//spring运用两种动态代理的方式,
//当被代理对象时接口并有对应的实现类的时候,采用的是jdk提供的代理方式(以下写法)
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("aop.xml");
Calculator calculator = context.getBean("calculatorImpl", Calculator.class);
calculator.mul(1,1);
System.out.println(calculator.getClass());
//当代理对象就是普通的一个类(没有实现接口)时,此时的spring采用的是CGLIB的代理方式(以下写法)
/* ClassPathXmlApplicationContext context1 = new ClassPathXmlApplicationContext("aop.xml");
CalculatorImpl calculatorImpl = context1.getBean("calculatorImpl", CalculatorImpl.class);
calculatorImpl.div(1,1);
System.out.println(calculatorImpl.getClass());
String s = ToStringBuilder.reflectionToString(calculatorImpl);
System.out.println(s);*/
}
- 小结
关于切面的配置和使用不仅仅局限于在配置文件中的使用,使用注解时完全可以取代配置文件的,这里仅仅是简单的一个demo,关于更多的用法,请自行学习和研究