Introductions (在 AspectJ 中被称为类型间声明)使一个切面能够声明 advice 对象实现一个给定的接口,并代表这些对象提供该接口的实现。
你可以通过使用 @DeclareParents注解来做一个 Introductions 。这个注解被用来声明匹配的类型有一个新的父类(因此而得名)。例如,给定一个名为 UsageTracked 的接口和一个名为 DefaultUsageTracked 的接口的实现,下面这个切面声明所有服务接口的实现者也实现 UsageTracked 接口(例如,通过 JMX 进行统计):
@Aspectpublic class UsageTracking {@DeclareParents(value="com.xzy.myapp.service.*+", defaultImpl=DefaultUsageTracked.class)public static UsageTracked mixin;@Before("com.xyz.myapp.CommonPointcuts.businessService() && this(usageTracked)")public void recordUsage(UsageTracked usageTracked) {usageTracked.incrementUseCount();}}
要实现的接口由被注解字段的类型决定。@DeclareParents 注解的值属性是 AspectJ 类型模式。任何匹配类型的 bean 都会实现 UsageTracked 接口。注意,在前面例子的 @Before,服务 Bean 可以直接作为 UsageTracked 接口的实现。如果以编程方式访问一个 Bean, 你会写下以下内容:
UsageTracked usageTracked = (UsageTracked) context.getBean("myService");
整个例子如下
声明一个接口
package cn.mrcode.study.springdocsread.aspect;/*** @author mrcode*/public interface UsageTracked {void incrementUseCount();}
实现这个接口
package cn.mrcode.study.springdocsread.aspect;import java.util.concurrent.atomic.AtomicInteger;/*** @author mrcode*/public class UsageTrackedImpl implements UsageTracked {final AtomicInteger is = new AtomicInteger();@Overridepublic void incrementUseCount() {System.out.println("执行了一次方法,当前是第 :" + is.getAndIncrement());}}
编写切面和 advice
package cn.mrcode.study.springdocsread.aspect;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.DeclareParents;import org.springframework.stereotype.Component;/*** @author mrcode*/@Aspect@Componentpublic class NotVeryUsefulAspect {@DeclareParents(value = "cn.mrcode.study.springdocsread.web.DemoService", defaultImpl = UsageTrackedImpl.class)public static UsageTracked mixin;@Before("execution(* cn.mrcode.study.springdocsread.web.DemoService.*(..)) && this(usageTracked)")public void recordUsage(UsageTracked usageTracked) {usageTracked.incrementUseCount();}}
上面切点要切入的服务类
package cn.mrcode.study.springdocsread.web;import org.springframework.stereotype.Component;/*** @author mrcode*/@Componentpublic class DemoService {public void test() {}public void test(String name) {}}
@DeclareParents的含义就是:让 DemoService 实现了一个 UsageTrackedImpl 类实现的接口,而这个接口的实现就是 UsageTrackedImpl; 所以下面这个强制转换就能转换了
package cn.mrcode.study.springdocsread;import org.aspectj.lang.annotation.Aspect;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import cn.mrcode.study.springdocsread.aspect.UsageTracked;import cn.mrcode.study.springdocsread.web.AppConfig;import cn.mrcode.study.springdocsread.web.DemoService;public class TestDemo {public static void main(String[] args) {final AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);final DemoService bean = ctx.getBean(DemoService.class);bean.test();UsageTracked usageTracked = ((UsageTracked) bean);System.out.println(bean);}}
