spring最重要的六种基本jar:
commons-logging.jar |
---|
spring-expression.jar |
spring-core.jar |
spring-context.jar |
spring-beans.jar |
spring-aop.jar |
本文还需两个jar:aopaliance.jar和aspectjweaver.jar!
如果本文的代码运行不出来,尝试添加以下的jar:(ojdbc的相关jar本文不需要,可以忽略)
applicationContext.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:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
default-autowire="byName"
xsi:schemaLocation="
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
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
现在步入正题!!!
AOP有四大通知类型:前置通知,后置通知,异常通知,环绕通知
先创建一个普通类,作为测试的方法
//该包位于Test
class function{
public void A(){
System.out.println("AAAAAAAAA");
}
public void B(int i){
int w = i/0;
System.out.println(w);
}
}
1.前置通知
前置通知会在指定的方法之前执行
//该类位于aop包
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class LogBefore implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("前置通知啦啦啦...");
}
}
接着在xml里面配置
<bean id="logBefore" class="aop.LogBefore"></bean>
<!--配置前置通知-->
<aop:config>
<aop:pointcut id="poioncut" expression="execution(public void Test.function.A())"/>
<aop:advisor advice-ref="logBefore" pointcut-ref="poioncut"></aop:advisor>
</aop:config>
之后执行A方法之前自动打印"前置通知啦啦啦…"
2.后置通知
//该类位于aop包
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class LogAfter implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("后置通知:目标对象:"+o1+",调用的方法名:"+method.getName()+",方法的参数个数:"+objects.length+",方法返回值"+o);
}
}
配置xml
<bean id="logAfter" class="aop.LogAfter"></bean>
<!--配置前置通知-->
<aop:config>
<aop:pointcut id="poioncut2" expression="execution(public void Test.function.A())"/>
<aop:advisor advice-ref="logAfter" pointcut-ref="poioncut2"></aop:advisor>
</aop:config>
之后执行A方法之后自动打印*****
3.异常通知
//该类位于aop包
import org.springframework.aop.ThrowsAdvice;
import java.lang.reflect.Method;
public class LogException implements ThrowsAdvice {
//根据异常通知接口的定义可以发现,异常通知的实现类 必须编写以下方法:
//void afterThrowing([Method,args,target],ThrowableSubclass):
public void afterThrowing(Method method, Object[] args, Object target, Throwable ex){
System.out.println("异常通知:目标对象:"+target+",方法名:"+method.getName()+",方法的参数:"+args.length+"异常类型:"+ex.getMessage());
}
}
配置xml
<bean id="logException" class="aop.LogException"></bean>
<aop:config>
<aop:pointcut id="poioncut3" expression="execution(public void Test.function.B())"/>
<aop:advisor advice-ref="logException" pointcut-ref="poioncut3"></aop:advisor>
</aop:config>
``
之后执行B方法遇到异常自动打印*****
4.环绕通知
环绕通知完全可以替代以上的三种通知,并且还会影响其他类型的通知,通知中的皇帝!
//该类位于aop包
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class LogAround implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {//环绕通知的本质是通过环绕其实现的
//方法体1...
Object result = null ;
try{
//方法体2...
System.out.println("用环绕通知实现的【前置通知】");
//invocation.proceed()之前的代码:前置通知
result = methodInvocation.proceed();//控制着目标方法的执行,addStudent
//result就是目标方法addStudent()方法的返回值
//invocation.proceed()之后的代码:后置通知
System.out.println("用环绕通知实现的【后置通知】");
System.out.println("目标对象target:"+methodInvocation.getMethod().getName()+"方法的参数个数:"+methodInvocation.getArguments().length+"方" +
"法的返回值:"+result);
}catch (Exception e){
//方法体3
//异常通知
System.out.println("用环绕通知实现的【异常通知】");
}
return result;
}
}
配置xml
<bean id="logAround" class="aop.LogAround"></bean>
<aop:config>
<aop:pointcut id="poioncut4" expression="execution(public void Test.function.B()) or execution(public void Test.function.A())"/>
<aop:advisor advice-ref="logAround" pointcut-ref="poioncut4"/>
</aop:config>
最后运行的结果大家应该能够想象出来。之所以我把它称之为通知中的皇帝,最主要的原因是当把LogAround类的return result 改为return 某个字符串,虽然环绕通知的返回值依旧是null,但我们惊奇的发现后置通知的返回值变成了该字符串!也就是他能修改方法的返回值!
基于注解形式的AOP
第一步,在IOC容器中声明对注解的支持:
<!--开启注解对AOP的支持-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
第二步编写通知类:
注意下面的@component,如果是通过这种方式将该实例纳入IOC容器,就别忘记配置扫描器~
package aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.lang.reflect.Array;
import java.util.Arrays;
//通过注解,把该类放入IOC容器(下面的注解相当于(<bean id="logAnnotation" class="***"></bean>))
@Component("logAnnotation")
@Aspect
public class LogAspectAnnotation {//@Aspect声明该类是个通知
@Before("execution(public * serviceimpl.StudentServiceImpl.addStudent(..))")//属性定义切点
public void myBefore(){//给任何方法加上Before,就会默认是前置通知
System.out.println("《注解形式的前置通知...》");
}
// 如果想通过注解形式 实现AOP,如果想获取 目标对象的一些参数,则需要使用一个对象:JoinPoint
@AfterReturning(pointcut = "execution(public * serviceimpl.StudentServiceImpl.addStudent(..))",returning = "returningValue")
public void myAfter(JoinPoint jp,Object returningValue){//只有有返回值的通知(后置通知)才需要Object参数拿返回值,还需要告诉Spring,就是在上面加kv对
System.out.println("《注解形式的后置通知....》目标对象:"+jp.getTarget()+",方法" +
"名:"+jp.getSignature().getName()+",参数列表:"+ Arrays.toString(jp.getArgs())+",返回值:"+returningValue);
}
//如果只捕获特定类型的异常通知,则下面的myException的括号中加入 JoinPoint pj,**Exception e 注解后面还需要加上KV对
//@AfterThrowing(pointcut="execution(public * serviceimpl.StudentServiceImpl.chu(int))",throwing="e")
//打印的时候加e.getMessage()
@AfterThrowing("execution(public * serviceimpl.StudentServiceImpl.chu(int))")
public void myException(){
System.out.println("《注解形式-异常通知》...");
}
//注意:想要在注解形式的环绕通知中加入目标对象的参数显示 用的是ProceedingJoinPoint 不是Joinpoint
@Around("execution(public * serviceimpl.StudentServiceImpl.addStudent(..)) execution(public * serviceimpl.StudentServiceImpl.chu(int))")
public void myAround(ProceedingJoinPoint jp){
// 方法执行之前:前置通知
System.out.println("jjjjjj方法执行之前:前置通知");
try{
// 方法执行时
// 方法执行之后:后置通知
jp.proceed();
System.out.println("jjjjjj方法执行之后:后置通知");
}catch(Throwable e){
//异常通知
System.out.println("jjjjjj异常通知");
}finally {
//最终通知
System.out.println("jjjjjj最终通知");
}
}
//最终通知
@After("execution(public * serviceimpl.StudentServiceImpl.addStudent(..))")
public void myFinal(){
System.out.println("jjjjjj最终通知嗷嗷嗷嗷");
}
}
好了再没有其他额外配置了!!!!
基于Shema的AOP实现:
通过配置将普通类,变成通知类
首先在applicationContext.xml 中需要aop命名空间:
类似接口的方式:
1.编写一个普通类:
package aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
//schema方式式
public class LogSchema {
//后置通知
public void afterReturning(JoinPoint jp,Object returnValue) throws Throwable {//Joinpaint适用于注解和schema方式
System.out.println("zzzzzzzzz后置通知:目标对象:"+jp.getThis()+",调用的方法名:"+jp.getSignature().getName()+",方法的参数个数:"+jp.getArgs().length+",方法返回值"+returnValue);
}
public void before() throws Throwable {
System.out.println("zzzzzzzzzzzzz前置....");
}
public void whenException(JoinPoint jp,NullPointerException e){
System.out.println("zzzzzzzzzzzzz异常:"+e.getMessage());
}
//schema方式和注解方式类似 不同之处:注解形式使用了@After schema形式在xml进行了多余的配对
//注意:环绕通知 会返回目标方法的返回值,因此返回值为Object
public Object around(ProceedingJoinPoint jp){
Object result = null;
System.out.println("schema的环绕前置");
try {
result = jp.proceed();
System.out.println("schema的环绕后置"+jp.getSignature().getName()+","+result);
}catch (Throwable e) {
System.out.println("schema的环绕异常置");
}
return result;
}
}
但是这次就需要继续配置IOC了:
<!--将准备转为通知的普通类纳入IOC容器-->
<bean id="LogSchema" class="aop.LogSchema"></bean>
<aop:config>
<aop:pointcut id="pcShema" expression="execution(public void serviceimpl.StudentServiceImpl.addStudent(entity.Student))"/>
<!--schema方式不需要aop:advisor -->
<aop:aspect ref="LogSchema">
<aop:before method="before" pointcut-ref="pcShema"/>
<aop:after-returning method="afterReturning" returning="returnValue" pointcut-ref="pcShema"/>
<aop:after-throwing method="whenException" throwing="e" pointcut-ref="pcShema"/>
<aop:around method="around" pointcut-ref="pcShema"/>
</aop:aspect>
</aop:config>
OK!!!!!!!