spring aop增强类

0. 增强分类

在这里插入图片描述

org.aopalliance.aop.Advice:aop联盟给出的接口规范,

package org.aopalliance.aop; 

/**
 * Tag interface for Advice. Implementations can be any type
 * of advice, such as Interceptors.
 */
public interface Advice {

}

1.前置增强

1.0: 继承树
在这里插入图片描述

1.1: org.springframework.aop.BeforeAdvice:前置增强

package org.springframework.aop;

import org.aopalliance.aop.Advice;

public interface BeforeAdvice extends Advice {

}

1.2: org.springframework.aop.MethodBeforeAdvice:前置增强

package org.springframework.aop;

import java.lang.reflect.Method;

import org.springframework.lang.Nullable;

/**
 * Advice invoked before a method is invoked. Such advices cannot
 * prevent the method call proceeding, unless they throw a Throwable.
 */
public interface MethodBeforeAdvice extends BeforeAdvice {

	/**
	 * 在一个指定的方法调用之前调用
	 * @param method 待调用的方法
	 * @param args 待调用方法的参数
	 * @param target 待调用方法的目标对象.可能是null.
	 * @throws Throwable 异常
	 */
	void before(Method method, Object[] args, @Nullable Object target) throws Throwable;

}

1.3: org.springframework.aop.AspectJMethodBeforeAdvice :前置增强
该类的方法实现是在其父类:org.springframework.aop.aspectj.AbstractAspectJAdvice,后面再说

package org.springframework.aop.aspectj;

import java.io.Serializable;
import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.lang.Nullable;

/**
 * Spring AOP advice that wraps an AspectJ before method.
 */
@SuppressWarnings("serial")
public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable {

	public AspectJMethodBeforeAdvice(
			Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {

		super(aspectJBeforeAdviceMethod, pointcut, aif);
	}


	@Override
	public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
		invokeAdviceMethod(getJoinPointMatch(), null, null);
	}

	@Override
	public boolean isBeforeAdvice() {
		return true;
	}

	@Override
	public boolean isAfterAdvice() {
		return false;
	}

}

接口如下:

package com.ghq.cloud.aop;

public interface Waiter {

    void greetingTo(String name);

    void serveTo(String name);
}

实现如下:

package com.ghq.cloud.aop;

public class NaiveWaiter implements Waiter {

    @Override
    public void greetingTo(String name) {

        System.out.println("greeting to :"+name);
    }

    @Override
    public void serveTo(String name) {

        System.out.println("serving to :"+name);
    }
}

前置增强的实现:

package com.ghq.cloud.aop;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class GreetingBeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        String clientName = (String) args[0];
        System.out.println("How are you! Mr."+clientName);
    }
}

测试类:

@Test
public void test01() {
    Waiter target = new NaiveWaiter();
    BeforeAdvice advice = new GreetingBeforeAdvice();

    //1. spring 提供的代理工厂
    ProxyFactory pf = new ProxyFactory();

    //1.1 指定代理接口
    //pf.setInterfaces(target.getClass().getInterfaces());

    //1.2 设置优化
    //pf.setOptimize(true);
    //2. 设置代理目标
    pf.setTarget(target);
    //3.  为代理目标添加增强
    pf.addAdvice(advice);
    //4. 生成代理实例
    Waiter proxy = (Waiter) pf.getProxy();
	System.out.println(proxy.getClass());//NaiveWaiter$$EnhancerBySpringCGLIB$$fdce4fb4
    proxy.greetingTo("john");
    proxy.serveTo("Tom");
}

输出结果:这里使用的CGLib代理

class com.ghq.cloud.aop.NaiveWaiter$$EnhancerBySpringCGLIB$$45749675
How are you! Mr.john
greeting to :john
How are you! Mr.Tom
serving to :Tom

1.4: spring xml配置 使用 ProxyFactory
xml配置如下:

<bean id="target" class="com.ghq.cloud.aop.NaiveWaiter"/>
<bean id="greetingAdvice" class="com.ghq.cloud.aop.GreetingBeforeAdvice"/>

<bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
      p:interceptorNames="greetingAdvice"
      p:interfaces="com.ghq.cloud.aop.Waiter"
      p:target-ref="target"/>

main方法如下:

public static void main(String[] args) {

   ApplicationContext context =
           new ClassPathXmlApplicationContext("classpath:beans2.xml");

   Waiter waiter = (Waiter) context.getBean("waiter");
   System.out.println(waiter.getClass());

   waiter.greetingTo("snow");
}

输出结果:

class com.sun.proxy.$Proxy4
How are you! Mr.snow
greeting to :snow

关于ProxyFactory我们下一篇文章再说

2.后置增强

2.0: 继承树
在这里插入图片描述

2.1: org.springframework.aop.BeforeAdvice:后置增强
后置增强在方法正常返回的情况下会被调用,如果方法抛出异常,那么后置增强不会调用。
后置增强可以拿到方法的返回值,但是不能改变这个返回值。

package org.springframework.aop;

import java.lang.reflect.Method;

import org.springframework.lang.Nullable;

public interface AfterReturningAdvice extends AfterAdvice {

	void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;

}

2.2: org.springframework.aop.BeforeAdvice:后置增强

public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice
		implements AfterReturningAdvice, AfterAdvice, Serializable {

	public AspectJAfterReturningAdvice(
			Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {

		super(aspectJBeforeAdviceMethod, pointcut, aif);
	}


	@Override
	public boolean isBeforeAdvice() {
		return false;
	}

	@Override
	public boolean isAfterAdvice() {
		return true;
	}

	@Override
	public void setReturningName(String name) {
		setReturningNameNoCheck(name);
	}

	@Override
	public void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable {
		if (shouldInvokeOnReturnValueOf(method, returnValue)) {
			invokeAdviceMethod(getJoinPointMatch(), returnValue, null);
		}
	}


	/**
	 * Following AspectJ semantics, if a returning clause was specified, then the
	 * advice is only invoked if the returned value is an instance of the given
	 * returning type and generic type parameters, if any, match the assignment
	 * rules. If the returning type is Object, the advice is *always* invoked.
	 * @param returnValue the return value of the target method
	 * @return whether to invoke the advice method for the given return value
	 */
	private boolean shouldInvokeOnReturnValueOf(Method method, @Nullable Object returnValue) {
		Class<?> type = getDiscoveredReturningType();
		Type genericType = getDiscoveredReturningGenericType();
		// If we aren't dealing with a raw type, check if generic parameters are assignable.
		return (matchesReturnValue(type, method, returnValue) &&
				(genericType == null || genericType == type ||
						TypeUtils.isAssignable(genericType, method.getGenericReturnType())));
	}

	/**
	 * Following AspectJ semantics, if a return value is null (or return type is void),
	 * then the return type of target method should be used to determine whether advice
	 * is invoked or not. Also, even if the return type is void, if the type of argument
	 * declared in the advice method is Object, then the advice must still get invoked.
	 * @param type the type of argument declared in advice method
	 * @param method the advice method
	 * @param returnValue the return value of the target method
	 * @return whether to invoke the advice method for the given return value and type
	 */
	private boolean matchesReturnValue(Class<?> type, Method method, @Nullable Object returnValue) {
		if (returnValue != null) {
			return ClassUtils.isAssignableValue(type, returnValue);
		}
		else if (Object.class == type && void.class == method.getReturnType()) {
			return true;
		}
		else {
			return ClassUtils.isAssignable(type, method.getReturnType());
		}
	}

}

后置增强的实现:

public class GreetingAfterAdvice implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {

        System.out.println("please enjoy yourself");
    }
}

xml配置:

    <bean id="target" class="com.ghq.cloud.aop.NaiveWaiter"/>
    <bean id="greetingBeforeAdvice" class="com.ghq.cloud.aop.GreetingBeforeAdvice"/>
    <bean id="greetingAfterAdvice" class="com.ghq.cloud.aop.GreetingAfterAdvice"/>

    <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:interceptorNames="greetingBeforeAdvice,greetingAfterAdvice"
          p:interfaces="com.ghq.cloud.aop.Waiter"
          p:target-ref="target"/>

注意增加的内容:

这里需要注意的是:p:interceptorNames 是String[]类型的,它接收增强的Bean的名称而不是增强Bean的实例。这里因为ProxyBeanFactory内部在生成代理类时,需要使用增强Bean的类,而不是增强Bean的实例,以织入增强类中所写的横切逻辑代码,因而可以说增强时类级别的

<bean id="greetingAfterAdvice" class="com.ghq.cloud.aop.GreetingAfterAdvice"/>
p:interceptorNames="greetingBeforeAdvice,greetingAfterAdvice"

main方法不变:参考前文(#1)的的main方法
输出结果如下:

How are you! Mr.snow
greeting to :snow
please enjoy yourself

3.环绕增强

3.0: 继承树
在这里插入图片描述

3.1: org.aopalliance.intercept.MethodInterceptor:环绕增强

package org.aopalliance.intercept;

/**
 * Intercepts calls on an interface on its way to the target. These
 * are nested "on top" of the target.
 *
 * <p>The user should implement the {@link #invoke(MethodInvocation)}
 * method to modify the original behavior. E.g. the following class
 * implements a tracing interceptor (traces all the calls on the
 * intercepted method(s)):
 *
 * <pre class=code>
 * class TracingInterceptor implements MethodInterceptor {
 *   Object invoke(MethodInvocation i) throws Throwable {
 *     System.out.println("method "+i.getMethod()+" is called on "+
 *                        i.getThis()+" with args "+i.getArguments());
 *     Object ret=i.proceed();
 *     System.out.println("method "+i.getMethod()+" returns "+ret);
 *     return ret;
 *   }
 * }
 * </pre>
 *
 * @author Rod Johnson
 */
@FunctionalInterface
public interface MethodInterceptor extends Interceptor {
	
	/**
	 * Implement this method to perform extra treatments before and
	 * after the invocation. Polite implementations would certainly
	 * like to invoke {@link Joinpoint#proceed()}.
	 * @param invocation the method invocation joinpoint
	 * @return the result of the call to {@link Joinpoint#proceed()};
	 * might be intercepted by the interceptor
	 * @throws Throwable if the interceptors or the target object
	 * throws an exception
	 */
	Object invoke(MethodInvocation invocation) throws Throwable;

}

环绕增强的实现:

package com.ghq.cloud.aop;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class GreetingInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation i) throws Throwable {

        System.out.println("method "+i.getMethod()+" is called on "+
                i.getThis()+" with args "+i.getArguments());

        Object o = i.proceed();

        System.out.println("method "+i.getMethod()+" returns "+o);
        return o;
    }
}

xml配置:

<bean id="greetingInterceptor" class="com.ghq.cloud.aop.GreetingInterceptor"/>

<bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
      p:interceptorNames="greetingInterceptor"
      p:interfaces="com.ghq.cloud.aop.Waiter"
      p:target-ref="target"/>

main方法不变:参考前文(#1)的的main方法
输出结果如下:

method public abstract void com.ghq.cloud.aop.Waiter.greetingTo(java.lang.String) is called on com.ghq.cloud.aop.NaiveWaiter@453da22c with args [Ljava.lang.Object;@71248c21
greeting to :snow
method public abstract void com.ghq.cloud.aop.Waiter.greetingTo(java.lang.String) returns null

4.异常抛出增强(场景:事务处理)

案例:
Service

public class ForumService {

    public void removeForum(int forumId){
        throw new RuntimeException("运行异常...");
    }

    public void updateForum(int forumId){
        throw new RuntimeException("数据更新异常...");
    }
}

异常抛出增强实现

package com.ghq.cloud.aop;

import org.springframework.aop.ThrowsAdvice;

import java.lang.reflect.Method;

public class TransactionManager implements ThrowsAdvice {

    public void afterThrowing(Method method, Object[] args, Object target, Exception ex){
        System.out.println("------------------");
        System.out.println("method:"+method.getName());
        System.out.println("抛出异常:"+ex.getMessage());
        System.out.println("成功回滚事务...");
    }
}

xml配置

<bean id="transactionManager" class="com.ghq.cloud.aop.TransactionManager"/>
<bean id="forumServiceTarget" class="com.ghq.cloud.aop.ForumService"/>
<bean id="forumService" class="org.springframework.aop.framework.ProxyFactoryBean"
      p:interceptorNames="transactionManager"
      p:proxyTargetClass="true"
      p:target-ref="forumServiceTarget"/>

5.引介增强(场景:性能监控)

定义一个是否支持监控的接口:

package com.ghq.cloud.aop;

public interface Monitorable {

    void setMonitorActive(boolean active);
}

通过继承DelegatingIntroductionInterceptor为目标类引入性能监视的可控功能。

public class ControllablePerformanceMonitor extends DelegatingIntroductionInterceptor implements Monitorable {

    private ThreadLocal<Boolean> map = new ThreadLocal<>();

    @Override
    public void setMonitorActive(boolean active) {
        map.set(active);
    }

    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {

        if(map.get()!=null && map.get()){
            System.out.println("开始 性能检测");

            Object o = super.invoke(mi);

            System.out.println("结束性能检测");
            return o;
        }else {
            return super.invoke(mi);
        }

    }
}

xml配置如下:

<bean id="monitor" class="com.ghq.cloud.aop.ControllablePerformanceMonitor"/>
<bean id="forumServiceTarget" class="com.ghq.cloud.aop.ForumService"/>
<bean id="forumService" class="org.springframework.aop.framework.ProxyFactoryBean"
      p:interfaces="com.ghq.cloud.aop.Monitorable"
      p:target-ref="forumServiceTarget"
      p:interceptorNames="monitor"
      p:proxyTargetClass="true"/>

service

public class ForumService {

    public void removeForum(int forumId){
        //throw new RuntimeException("运行异常...");
        System.out.println("根据id移除对象");
    }

    public void updateForum(int forumId){
        throw new RuntimeException("数据更新异常...");
    }
}

main方法:

public static void main(String[] args) {

    ApplicationContext context =
            new ClassPathXmlApplicationContext("classpath:beans2.xml");

    ForumService forumService = (ForumService) context.getBean("forumService");
    forumService.removeForum(1);

    System.out.println("---------------------");
    Monitorable monitorable = (Monitorable) forumService;
    monitorable.setMonitorActive(true);
    forumService.removeForum(1);
}

输出结果:

根据id移除对象
---------------------
开始 性能检测
根据id移除对象
结束性能检测

结束。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值