Spring——AOP切⾯(实现消息通知)消息通知通常有5种:
前置通知
返回通知
异常通知
后置通知
环绕通知
1.采⽤注解的⽅式
这⾥使⽤简单计算器的例⼦作为⽰范:
声明⼀个Calculator的接⼝:
public interface Calculator {
int add(int i,int j);
int sub(int i,int j);
int mul(int i,int j);
int div(int i,int j);
}
这⾥只做简单的加减乘除运算。
实现该接⼝:
@Component
public class CalculatorImpl implements Calculator{
@Override
public int add(int i, int j) {
int result=i+j;
return result;
}
@Override
public int sub(int i, int j) {
int result=i-j;
return result;
}
@Override
public int mul(int i, int j) {
int result=i*j;
return result;
}
@Override
public int div(int i, int j) {
int result=i/j;
return result;
}
}
开始有⼀个@Component⽤来实例化⼀个bean对象。
然后我们想在每个⽅法执⾏前输出执⾏⽅法的名称和参数就需要配置⼀个切⾯对象了。
//把这个类声明为⼀个切⾯:需要把该类放⼊到IOC容器中,再声明为⼀个切⾯
@Order //指定切⾯的优先级,值越⼩级别越⾼
@Aspect
@Component
public class LoggingAspect {
//声明该⽅法是⼀个前置通知
@Before("execution(public int com.spring.aop.impl.Calculator.*(int, int))")
public void beforeMethod(JoinPoint joinPoint) {
String Signature().getName();
List<Object> args=Arrays.Args());
System.out.println("The method "+methodName+" begins with"+args);
}
}
@Order是⽤来指定切⾯的优先级的,如果声明了多个切⾯,则可以根据@Order指定的值来判断执⾏的顺序,默认值越⼩的优先级越⾼。@Aspect就是表⾯该类是⼀个切⾯对象。
此时只要是Calculator中的⽅法被执⾏前就会输出相应的参数信息了。
当然,如果我们不需要所有的⽅法被执⾏前都输出该信息,我们同样可以指定Calculator中特定的⽅法,只需要把@Before中的参数修改下:
@Before("execution(public int com.spring.aop.impl.Calculator.add(int, int))")
这样就只在执⾏add⽅法时才会有提⽰信息。
同样,我们也可以实现后置,返回,异常,环绕等通知。
后置通知:
//执⾏完⽅法之后掉⽤,⽆论是否存在异常
@After("execution(public int com.spring.aop.impl.Calculator.*(int, int))")
public void afterMethod(JoinPoint joinPoint) {
String Signature().getName();
System.out.println("The method "+methodName+" end ");
}
返回通知:
@AfterReturning(value="execution(public int com.spring.aop.impl.Calculator.*(int, int))",
returning="result")
public void afterReturning(JoinPoint joinPoint,Object result) {
String Signature().getName();
System.out.println("The method "+methodName+" result: "+result);
}
异常通知:
@AfterThrowing(value="execution(public int com.spring.aop.impl.Calculator.*(int, int))",
throwing="ex")
public void afterThrowing(JoinPoint joinPoint,Exception ex) {
String Signature().getName();
System.out.println("The method "+methodName+" Exception: "+ex);
}
环绕通知:
//类似动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执⾏⽬标⽅法
//必须有返回值,返回值即为⽬标⽅法的返回值
@Around("execution(public int com.spring.aop.impl.Calculator.*(int, int))")
public Object aroundMethod(ProceedingJoinPoint p) {
System.out.println("aroundMtethod");
Object result=null;
try {
//前置
result=p.proceed();
//后置
} catch (Throwable e) {
// TODO Auto-generated catch block
//异常
e.printStackTrace();
}
/
/返回
return result ;
}
环绕通知是功能最强⼤的通知,但也是最复杂的通知,因为它也包含了其它的四种通知,如果所需要的通知⽐较简单基础就使⽤其余四种通知就已经⾜够了。
配置bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="/schema/beans"
xmlns:xsi="/2001/XMLSchema-instance"
xmlns:aop="/schema/aop"
xmlns:context="/schema/context"
xsi:schemaLocation="/schema/beans /schema/beans/spring-beans.xsd
/schema/context /schema/context/spring-context-4.3.xsd
/schema/aop /schema/aop/spring-aop-4.3.xsd">
<context:component-scan base-package="com.spring.aop.impl"></context:component-scan>
<!-- 使AspjectJ注解起作⽤:⾃动为匹配的类⽣成代理对象 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
记住需要选中bean的namespace中的aop和context 。
测试:
public static void main(String[] args) {
//1.创建IOC容器
ApplicationContext ctx=new ClassPathXmlApplicationContext("l");
Calculator Bean(Calculator.class);
int result=calculator.add(1, 2);
System.out.println(result);
result=calculator.div(4, 2);
System.out.println(result);
}
输出结果:
aroundMtethod
The method add begins with[1, 2]
The method add end
The method add result: 3
3
aroundMtethod
The method div begins with[4, 2]
The method div end
The method div result: 2
2
2.使⽤aopspring ioc注解
基本的类和使⽤注解的都是相同的,只需要去除那些注解就⾏,然后修改下配置⽂件。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="/schema/beans"
xmlns:xsi="/2001/XMLSchema-instance"
xmlns:aop="/schema/aop"
xmlns:context="/schema/context"
xsi:schemaLocation="/schema/beans /schema/beans/spring-beans.xsd
/schema/context /schema/context/spring-context-4.3.xsd
/schema/aop /schema/aop/spring-aop-4.3.xsd">
<bean id="t" class="com.l.CalculatorImpl"></bean>
<!-- 配置切⾯的bean -->
<bean id="loggingAspect" class="com.l.LoggingAspect"></bean>
<!-- 配置AOP -->
<aop:config>
<aop:pointcut expression="execution(* com.l.Calculator.*(int,int))" id="pointcut"/>
<aop:aspect ref="loggingAspect" order="2">
<aop:before method="beforeMethod" pointcut-ref="pointcut"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="ex"/>
</aop:aspect>
</aop:config>
</beans>
默认都是基于接⼝的代理,也就是aop:pointcut的expression中设置的往往都是关于接⼝的,当然也可以设置基于类的代理,只需要将<aop:config>的proxy-target-class属性设置为true就⾏了,默认是false。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论