Introductions (在 AspectJ 中被称为类型间声明)使一个切面能够声明 advice 对象实现一个给定的接口,并代表这些对象提供该接口的实现。
你可以通过使用 @DeclareParents
注解来做一个 Introductions 。这个注解被用来声明匹配的类型有一个新的父类(因此而得名)。例如,给定一个名为 UsageTracked 的接口和一个名为 DefaultUsageTracked 的接口的实现,下面这个切面声明所有服务接口的实现者也实现 UsageTracked 接口(例如,通过 JMX 进行统计):
@Aspect
public 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();
@Override
public 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
@Component
public 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
*/
@Component
public 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);
}
}