一、通过实现(implements)的方式增强
BeforeLog:
package cn.log;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class BeforeLog implements MethodBeforeAdvice {
/**
* method 被调用的方法对象
* args 被调用的方法的参数
* target 被调用的方法的目标对象
* */
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("before---"+target.getClass().getName()+"的"+method.getName()+"方法被执行");
}
}
AfterLog:
package cn.log;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
public class AfterLog implements AfterReturningAdvice {
/**
* 目标方法执行后的通知
* returnValue 返回值
* method 被调用的方法对象
* args 被调用的方法对象的参数
* target 被调用的方法对象的目标对象
* */
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("after---"+target.getClass().getName()+"的"+method.getName()+"被成功执行,返回值是"+returnValue);
}
}
AroundLog:
package cn.log;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class AroundLog implements MethodInterceptor {
public Object invoke(MethodInvocation arg0) throws Throwable {
Object target = arg0.getThis(); //获取被代理的对象
Method method = arg0.getMethod(); //获取被代理的方法
Object[] args = arg0.getArguments(); //获取方法参数
System.out.println("环绕---调用" + target + "的 " + method.getName() + "方法。方法入参:"+ Arrays.toString(args));
try { Object result = arg0.proceed();//调用目标方法,获取返回值
System.out.println("环绕---调用" + target + "的 " + method.getName() + "方法。"
+ "方法返回值:" + result);
return result;
} catch (Throwable e) {
System.out.println(method.getName() + " 方法发生异常" + e);
throw e;
}
}
}
ErrorLog:
package cn.log;
import org.aspectj.apache.bcel.classfile.Method;
import org.springframework.aop.ThrowsAdvice;
/**
* 方法名必须是afterThrowing。方法的入参只有最后一个是必须的,前三个入参是可选的,但是前三个参数要么都提供,要么一个也不提供。正确的声明方法举例:
afterThrowing(Method method, Object[] args, Object target, SQLException ex)
afterThrowing(SQLException ex)
afterThrowing(RuntimeException ex)
错误的声明方法举例:
catchThrowing(RuntimeException ex):方法名错误
afterThrowing(Method method, RuntimeException ex):参数列表错误
* */
public class ErrorLog implements ThrowsAdvice{
public void afterThrowing(Method method, Object[] args, Object target,
RuntimeException e) {
System.out.println(method.getName() + " 方法发生异常:" + e);
}
}
---------
UserService接口:
package cn.service;
public interface UserService {
public void add();
public String update(int i);
public void delete();
public void search();
}
UserServiceImpl:
package cn.service;
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("增加用户");
}
@Override
public String update(int i) {
System.out.println("更新用户");
return "success";
}
@Override
public void delete() {
System.out.println("删除用户");
}
@Override
public void search() {
System.out.println("查询用户");
}
}
beans.xml
<bean id="userService" class="cn.service.UserServiceImpl"/>
<bean id="beforeLog" class="cn.log.BeforeLog"/>
<bean id="afterLog" class="cn.log.AfterLog"/>
<bean id="errorLog" class="cn.log.ErrorLog"/>
<bean id="aroundLog" class="cn.log.AroundLog"/>
<aop:config>
<aop:pointcut expression="execution(* cn.service.UserServiceImpl.*(..))" id="pointcut"/>
<aop:advisor advice-ref="aroundLog" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="errorLog" pointcut-ref="pointcut"/>
</aop:config>
--------------------
Test:
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.service.UserService;
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
UserService userservice = (UserService)ac.getBean("userService");
//userservice.delete();
userservice.update(1);
}
}
输出:
总结:
①:环绕增强在目标方法前后(环绕前、环绕后)都可以插入增强处理
②:环绕增强是spring中最强大的增强,Spring把目标方法的控制权全部给了它,可以获取或者修改目标方法的参数和返回值,并且可以对方法进行异常处理和决定方法是否执行
注意一点:如果<aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>放在
<aop:advisor advice-ref="aroundLog" pointcut-ref="pointcut"/>之前,执行的顺序会变得不一样
这仅仅是before和around的环绕前有这样的效果,after始终都是在方法执行后执行,然后再到around的环绕后执行。
二、非注解的自定义类实现aop增强
Log:
package cn.log;
/**
* 自定义类实现aop
* */
public class Log {
public void before()
{
System.out.println("方法执行前---55566-----");
}
public void after()
{
System.out.println("方法执行后--------");
}
}
beans.xml
<bean id="userService" class="cn.service.UserServiceImpl"/>
<bean id="log" class="cn.log.Log"/>
<aop:config>
<aop:aspect ref="log">
<aop:pointcut expression="execution(* cn.service.UserServiceImpl.*(..))" id="pointcut"/>
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
除了before、after之外,还可以自定义around、after-returning、after-throwing
三、使用注解实现自定义aop增强
log:
package cn.log;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
/**
* 自定义类实现aop
* +++++++使用注解!!!
* */
@Aspect
public class Log {
@Before("execution(* cn.service.UserServiceImpl.*(..))")
public void before()
{
System.out.println("方法执行前--------");
}
@After("execution(* cn.service.UserServiceImpl.*(..))")
public void after()
{
System.out.println("方法执行后--------");
}
@Around("execution(* cn.service.UserServiceImpl.*(..))")
public void aroud(ProceedingJoinPoint jp) throws Throwable
{
System.out.println("环绕前");
System.out.println("签名:"+jp.getSignature());
// Object result = jp.proceed();
jp.proceed();
System.out.println("环绕后");
// return result;
}
}
beans.xml
<bean id="userService" class="cn.service.UserServiceImpl"/>
<bean id="log" class="cn.log.Log"/>
<aop:aspectj-autoproxy/>
Test:
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
UserService userservice = (UserService)ac.getBean("userService");
//userservice.add();
userservice.delete();
}
输出:
三种方式定义增强使用建议:
Spring在定义切面时提供了多种选择,应根据项目的具体情况做出选择:
1、通过接口实现增强处理是较低版本Spring AOP的做法,如果在一个使用低版本Spring AOP开发的项目上进行升级,
可以考虑使用<aop:advisor>复用已经存在的增强类;
2、如果项目采用JDK 5.0或以上版本,可以考虑使用@AspectJ注解方式,减少配置的工作量;
3、如果不愿意使用注解或项目采用的JDK版本较低无法使用注解,则可以选择使用<aop:aspect>配合普通JavaBean的形式。