Spring AOP三种方式定义增强

2023-11-13

一、通过实现(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的形式。





本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring AOP三种方式定义增强 的相关文章

随机推荐