1. 程式人生 > >基於代理的spring aop中,切面的實現

基於代理的spring aop中,切面的實現

基於代理的spring aop中,使用介面Advisor表示切面.

  • 對目標物件織入通知可使用PointAdvisor介面及其子類,定義切面.其子類中有便捷的DefaultPointcutAdvisor實現類可使用.
  • 對目標物件織入引入功能時,可使用IntroductionAdvisor介面.
  • 切面即切點和通知的組合,可使用DefaultPointcutAdvisor來定義切點和通知.

  1. org.springframework.aop.Pointcut的結構
  2. org.aopalliance.aop.Advice的結構

關於PointCut的實現,又需要有ClassFilter和MethodMatcher來匹配目標物件型別和目標物件的方法.


目標物件類

 

package siye;
public class TargetObj_reuse
{
	public void work()
	{
		System.out.println("work....");
	}
	public void wake(int num)
	{
		System.out.println("user_wake..." + num);
	}
}

對目標物件引入新特性的介面

package siye;
public interface NewFeature
{
	void eat();
}

前置通知實現類

package siye;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class BeforeAdviceImpl implements MethodBeforeAdvice
{
	@Override
	public void before(Method method, Object[] args,
			Object target) throws Throwable
	{
		System.out.println("方法即將被呼叫.");
	}
}

引入實現類

package siye;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
public class IntroductionAdviceImpl extends
		DelegatingIntroductionInterceptor implements
		NewFeature
{
	private static final long serialVersionUID =
			-543070161703560988L;
	@Override
	public Object invoke(MethodInvocation mi)
			throws Throwable
	{
		return super.invoke(mi);
	}
	@Override
	public void eat()
	{
		System.out.println("eat...");
	}
}

目標物件型別匹配簡單實現類

package siye;
import org.springframework.aop.ClassFilter;
public class GenericClassFilterImpl implements ClassFilter
{
	@Override
	public boolean matches(Class<?> clazz)
	{
		if (TargetObj_reuse.class.isAssignableFrom(clazz))
		{// 在此,可配置要切入的物件型別的集合.
			return true;
		}
		return false;
	}
}

切點實現類,包含多種情況切點是切點實現的非共有類

package siye;
import java.lang.reflect.Method;
import java.util.regex.Pattern;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.DynamicMethodMatcher;
import org.springframework.aop.support.StaticMethodMatcher;
/**
 * 標記介面
 */
public interface AllPointcut
{
}
/**
 * 定義靜態方法切點
 * 類說明:
 * MyStaticPointcutImpl,實現切點.
 * StaticMethodMatcherImpl,實現方法匹配.
 */
class MyStaticPointcutImpl implements Pointcut
{// 定義方法和型別匹配
	@Override
	public ClassFilter getClassFilter()
	{
		return new GenericClassFilterImpl();
	}
	@Override
	public MethodMatcher getMethodMatcher()
	{
		return new StaticMethodMatcherImpl();
	}
}
class StaticMethodMatcherImpl extends StaticMethodMatcher
{// 定義靜態方法匹配
	@Override
	public boolean matches(Method method,
			Class<?> targetClass)
	{
		if ("work".equals(method.getName()))
		{
			return true;
		}
		return false;
	}
}
/**
 * 定義動態方法切點.
 * 介面DynamicMethodMatcher.
 * Convenient abstract superclass for dynamic method matchers,
 * which do care about arguments at runtime.
 * 
 * MyDynamicPointcutImpl,實現切點.
 * DynamicMethodMatcherImpl,實現方法匹配.
 */
class MyDynamicPointcutImpl implements Pointcut
{// 定義方法和型別匹配
	@Override
	public ClassFilter getClassFilter()
	{
		return new GenericClassFilterImpl();
	}
	@Override
	public MethodMatcher getMethodMatcher()
	{
		return new DynamicMethodMatcherImpl();
	}
}
class DynamicMethodMatcherImpl extends DynamicMethodMatcher
{
	@Override
	public boolean matches(Method method,
			Class<?> targetClass, Object... args)
	{
		if (Pattern.matches("^w\\w+$", method.getName())
				&& args.length > 0)
		{// 匹配以開頭且有引數的方法
			// System.out.println(targetClass);
			return true;
		}
		return false;
	}
}

測試類

package siye;
import org.aopalliance.aop.Advice;
import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.Advisor;
import org.springframework.aop.Pointcut;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
public class UnitTest
{
	TargetObj_reuse targetObj;// 宣告目標物件
	Advice adviceImpl;// 宣告通知實現
	DefaultPointcutAdvisor advisor;// 宣告切面
	ProxyFactory proxyFactory; // 宣告代理工廠
	Pointcut pointcutImpl; // 宣告切點
	@Before
	public void prepare()
	{
		// 例項化目標物件
		targetObj = new TargetObj_reuse();
		// 例項化前置通知
		adviceImpl = new BeforeAdviceImpl();
		// 例項化通用的切面
		advisor = new DefaultPointcutAdvisor();
		// 例項化代理工廠
		proxyFactory = new ProxyFactory();
		// 設定目標代理
		proxyFactory.setTarget(targetObj);
		// 強制使用cglib代理
		proxyFactory.setProxyTargetClass(true);
	}
	@Test
	public void testStaticAspect()
	{
		pointcutImpl = new MyStaticPointcutImpl();
		advisor.setPointcut(pointcutImpl);// 設定切面的切點
		advisor.setAdvice(adviceImpl); // 設定切面的通知
		proxyFactory.addAdvisor(advisor);
		TargetObj_reuse obj =
				(TargetObj_reuse) proxyFactory.getProxy();
		obj.work();// 前置通知對此類的此方法生效
	}
	@Test
	public void testDynamicAspect()
	{
		pointcutImpl = new MyDynamicPointcutImpl();
		// 設定切面的切點
		advisor.setPointcut(pointcutImpl);
		// 設定切面的通知
		advisor.setAdvice(adviceImpl);
		proxyFactory.addAdvisor(advisor);
		TargetObj_reuse obj =
				(TargetObj_reuse) proxyFactory.getProxy();
		obj.work();
		obj.wake(12);
	}
	@Test
	public void testIntroductionAspect()
	{
		// 因引入,要使用此通知器.
		Advice advice = new IntroductionAdviceImpl();
		Advisor advisor =
				new DefaultIntroductionAdvisor(advice);
		proxyFactory.addAdvisor(advisor);
		TargetObj_reuse obj0 =
				(TargetObj_reuse) proxyFactory.getProxy();
		obj0.work();
		NewFeature obj1 = (NewFeature) obj0;
		obj1.eat();
	}
}


  • 基於xml的實現,可借用ProxyFactoryBean來實現,具體的實現區別是設定其屬性.
  • 可直接實現Advisor介面下的特定通知器,來完成自定義的切面(方法與上類似).
  • 也可直接實現Pointcut介面下的特定通知器,來完成自定義的切面(方法與上類似).
  • 以上的程式碼例項,是以實現MethodMatcher介面下的特定介面或類來實現的.
Advisor介面下的特定切面 Pointcut介面下的特定切點 MethodMatcher介面下的匹配方法
DefaultIntroductionAdvisor StaticMethodMatcherPointcut ControlFlowPointcut
DefaultPointcutAdvisor DynamicMethodMatcher DynamicMethodMatcher
NameMatchMethodPointcutAdvisor AnnotationMethodMatcher StaticMethodMatcher
RegexpMethodPointcutAdvisor ExpressionPointcut TrueMethodMatcher
StaticMethodMatcherPointcutAdvisor ControlFlowPointcut IntroductionAwareMethodMatcher
e.g. ComposablePointcut e.g.
  e.g.