基於代理的spring aop中,切面的實現
阿新 • • 發佈:2018-12-12
基於代理的spring aop中,使用介面Advisor表示切面.
- 對目標物件織入通知可使用PointAdvisor介面及其子類,定義切面.其子類中有便捷的DefaultPointcutAdvisor實現類可使用.
- 對目標物件織入引入功能時,可使用IntroductionAdvisor介面.
- 切面即切點和通知的組合,可使用DefaultPointcutAdvisor來定義切點和通知.
- org.springframework.aop.Pointcut的結構
- 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. |