Spring学习(十)-AOP编程【下】

SpringAOP代理机制

SpringAOP使用了两种代理机制:一种是基于JDK的动态代理;另一种是基于CGLib的动态代理。之所以需要两种代理机制,很大程度上是因为JDK本身直提供了接口代理,而不支持类的代理。对于singleton的代理对象或者具有实例池的代理,因为无须频繁创建代理对象,所以比较适合用CGLib动态代理技术,反之适合用JDK动态代理技术。
SpringAOP通过pointcut(切点)指定在哪些类的哪些方法上织入横切逻辑,通过Advice(增强)描述横切逻辑和方法的具体织入点(方法前,方法后,方法的两端等)。此外,Spirng通过Advisor(切面)将pointcut和advisor两者组装起来。有了Advisor的信息,Spring就可以利用JDK或CGLib的动态代理技术采用统一的方式为Bean创建织入切面的代理对象了。

增强类型

  • 前置增强:org.springframework.aop.BeforeAdvice代表前置增强,因为Spring只支持方法级的增强,所以MethodBeforeAdivce是目前可用的前置增强,表示在目标方法执行前实施增强。
  • 后置增强:org.springframework.aop.AfterReturningAdvice代表后置增强,表示在目标方法执行后实施增强。
  • 环绕增强:org.aopalliance.intercept.MethodInterceptor代表环绕增强,表示在目标方法执行前后实施增强。
  • 异常抛出增强:org.springframework.aop.ThrowsAdvice代表抛出异常增强,表示在目标方法抛出异常后实施增强。
  • 引介增强:org.springframework.aop.IntroductionInterceptor代表引介增强,表示在目标类中添加一些新的方法和属性,所以引介增强的连接点是类级别,而非方法级别的。

下面举例前置增强、后置增强、环绕增强、引介增强。

前置增强:
package advice;

public interface Waiter {
	
	void greetTo(String name);
	void serveTo(String name);

}

package advice;

public class NaiveWaiter implements Waiter {

	@Override
	public void greetTo(String name) {
		System.out.println("greet to "+name+"....");
	}

	@Override
	public void serveTo(String name) {
		System.out.println("serve to "+name+"....");

	}

}

package advice;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class GreetingBeforeAdvice implements MethodBeforeAdvice {

	@Override
	public void before(Method arg0, Object[] args, Object obj)
			throws Throwable {
		String clientName = (String) args[0];
		System.out.println("Hello! Mr."+clientName+"!");

	}

}

BeforeAdvice是前置增强的接口,方法前置增强的MethodBeforeAdvice接口是其子类。MethodBeforeAdvice 接口仅定义了唯一的方法before(Method method Object[] args, Object obj)throws Throwable,method为目标类的方法,args为目标类方法的入参;obj为目标类实例。

package advice;

import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;

public class TestBeforeAdivce {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Waiter target = new NaiveWaiter();
		BeforeAdvice advice = new GreetingBeforeAdvice();
		//Spring提供的代理工厂
		ProxyFactory pf = new ProxyFactory();
		//设置代理目标
		pf.setTarget(target);
		//为代理目标添加增强
		pf.addAdvice(advice);
		//生成代理实例
		Waiter proxy = (Waiter) pf.getProxy();
		proxy.greetTo("Ytomson");
		proxy.serveTo("Jhon");

	}

}

运行结果:
Hello! Mr.Ytomson! ---------通过前置增强引入
greet to Ytomson…
Hello! Mr.Jhon! ------------通过前置增强引入
serve to Jhon…

在Spring中配置,通过ProxyFactoryBean配置代理

<bean id="greetingBefore" class="advice.GreetingBeforeAdvice"></bean>
<bean id="target" class="advice.NaiveWaiter"></bean>
<bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
	p:proxyInterfaces="advice.Waiter"
	p:interceptorNames="greetingBefore"
	p:target-ref="target"></bean>

proxyInterfaces指定代理的接口,如果是多个接口,请使用<list>元素。
interceptorNames指定使用的增强。
target-ref指定对哪个Bean进行代理。

ProxyFactoryBean是FactoryBean接口的实现类,它负责实例化一个Bean。ProxyFactoryBean负责为其他Bean创建代理实例,它内部使用ProxyFactory来完成这一个工作。

package advice;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeansTestBeforeAdivce {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:advice/beans.xml");
		Waiter waiter = (Waiter) ctx.getBean("waiter");
		waiter.greetTo("Ytomson");

	}

}

运行结果:
Hello! Mr.Ytomson!
greet to Ytomson…

后置增强:
package advice;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;



public class GreetingAfterAdvice implements AfterReturningAdvice {


	@Override
	public void afterReturning(Object arg0, Method arg1, Object[] arg2,
			Object arg3) throws Throwable {
		System.out.println("Please enjoy yourself!");
		
	}

}

添加后置增强:

   <bean id="greetingBefore" class="advice.GreetingBeforeAdvice"></bean>
    <bean id="greetingAfter" class="advice.GreetingAfterAdvice"></bean>
    <bean id="target" class="advice.NaiveWaiter"></bean>
    <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
    	p:proxyInterfaces="advice.Waiter"
    	p:interceptorNames="greetingBefore,greetingAfter"
    	p:target-ref="target"></bean>

运行结果:
Hello! Mr.Ytomson! ---------前置增强引入的逻辑
greet to Ytomson…
Please enjoy yourself! ---------后置增强引入的逻辑

环绕增强:
package advice;

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

public class GreetingInterceptor implements MethodInterceptor {

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

		Object[] args = invocation.getArguments();//目标方法入参
		String clientName = (String) args[0];
		System.out.println("Hello! Mr."+clientName+"!");
		Object obj = invocation.proceed();//通过反射机制调用目标方法
		System.out.println("Please enjoy yourself!");
		return obj;
	}

}

添加环绕增强:

    <bean id="greetingBefore" class="advice.GreetingBeforeAdvice"></bean>
    <bean id="greetingAfter" class="advice.GreetingAfterAdvice"></bean>
    <bean id="greetingAround" class="advice.GreetingInterceptor"></bean>
    <bean id="target" class="advice.NaiveWaiter"></bean>
    <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
    	p:proxyInterfaces="advice.Waiter"
    	p:interceptorNames="greetingAround"
    	p:target-ref="target"></bean>

运行结果:

Hello! Mr.Ytomson!
greet to Ytomson…
Please enjoy yourself!

可见,这是前置增强和后置增强的联合效果。

引介增强:
package advice;

public interface Monitorable {
	void setMonitorActive(boolean active);

}

通过该接口方法控制业务类性能监控功能的激活和关闭状态。
下面,通过扩展DelegatingIntroductionInterceptor为目标类引入性能监控的可控功能

package advice;

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;

public class ControllablePerformanceMonitor extends DelegatingIntroductionInterceptor implements Monitorable {

	private ThreadLocal<Boolean> MonitorStatusMap = new ThreadLocal<Boolean>();
	@Override
	public void setMonitorActive(boolean active) {
		MonitorStatusMap.set(active);
	}
	//拦截方法
	public Object invoke(MethodInvocation mi) throws Throwable{
		
		Object obj = null;
		if(MonitorStatusMap.get()!=null&&MonitorStatusMap.get()){
			PerformanceMonitor.begin(mi.getClass().getName()+"."+mi.getMethod().getName());
			obj = super.invoke(mi);
			PerformanceMonitor.end();
		}else{
			obj = super.invoke(mi);
		}
		
		return obj;
		
	}

}

配置引介增强:

    <bean id="pmonitor" class="advice.ControllablePerformanceMonitor"></bean>
    <bean id="forumServiceTarget" class="advice.ForumServiceImpl"></bean>
    <bean id="forumService" class="org.springframework.aop.framework.ProxyFactoryBean"
    	p:interfaces="advice.Monitorable"
    	p:target-ref="forumServiceTarget"
    	p:interceptorNames="pmonitor"
    	p:proxyTargetClass="true"></bean>

由于引介增强一定要通过创建子类来生成代理,所以需要强制使用CGLib,否则会报错。

测试引介增强:

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeansTestBeforeAdivce {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:advice/beans.xml");
		//Waiter waiter = (Waiter) ctx.getBean("waiter");
		//waiter.greetTo("Ytomson");
		ForumService forumService = (ForumService) ctx.getBean("forumService");
		forumService.removeForum(10);
		forumService.removeTopic(1022);
		
		Monitorable monitorable = (Monitorable) forumService;
		monitorable.setMonitorActive(true);
		
		forumService.removeForum(10);
		forumService.removeTopic(1022);
	}

}

运行结果:
删除forum记录:10
删除topic记录:1022
begin monitor
删除forum记录:10
begin monitor
org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.removeForum花费40毫秒。
begin monitor

删除topic记录:1022
begin monitor
org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.removeTopic花费20毫秒。

在一开始只有业务逻辑执行,性能监视的功能没有执行,之后性能监视功能正常启用,两个业务方法都启用了性能监视的功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值