SpringAOP:代表一个类型声明额外的方法或字段



在Spring AOP的规范中提到:

简介:代表类型声明其他方法或字段。SpringAOP允许您向任何建议的对象引入新的接口(以及相应的实现(。例如,您可以使用介绍来使bean实现IsModified接口,以简化缓存。(介绍在AspectJ社区中被称为类型间声明。(

我不知道如何为建议的类添加新字段,如果你有经验,你能举个例子吗?

演示Spring AOP引入的代码得到了一个很长的答案。希望这能帮助

考虑以下接口

package rg.test.aop;
public interface UserService {
void sayHello();
}

以及两种实现

用户服务OneImpl

package rg.test.aop.one;
import org.springframework.stereotype.Service;
import rg.test.aop.UserService;
@Service
public class UserServiceOneImpl implements UserService {
@Override
public void sayHello() {
System.out.println("One");
}
}

和用户服务TwoImpl

package rg.test.aop.two;
import org.springframework.stereotype.Service;
import rg.test.aop.UserService;
@Service
public class UserServiceTwoImpl implements UserService {
@Override
public void sayHello() {
System.out.println("Two");
}
}

以及将与AOP 一起介绍的接口及其实现

package rg.test.aop.intro;
public interface LoginTracker {
String FIELD = "Field";
Integer incrementLoginCount();
}

实施

package rg.test.aop.intro;
public class DefaultLoginTracker implements LoginTracker {
Integer count = 5;
@Override
public Integer incrementLoginCount() {
return ++count;
}
}

Spring AOP建议在包rg.test.aop.two下的所有类中引入相同的内容

package rg.test.aop.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.stereotype.Component;
import rg.test.aop.intro.DefaultLoginTracker;
import rg.test.aop.intro.LoginTracker;
@Aspect
@Component
public class IntroTestAspect {
@DeclareParents(value="rg.test.aop.two.*+", defaultImpl=DefaultLoginTracker.class)
LoginTracker tracker;
}

要实现的接口由注释字段的类型决定。(此处为LoginTracker(

任何匹配类型的bean都实现LoginTracker接口。

现在,当您运行以下测试类时

//package and imports
public class IntroductionTest {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(IntroductionConfig.class);
LoginTracker tracker = ctx.getBean(LoginTracker.class);
System.out.println(tracker);
System.out.println("------------------------");
UserService userOne = (UserService) ctx.getBean("userServiceOneImpl");
UserService userTwo = (UserService) ctx.getBean("userServiceTwoImpl");
printDetails(userOne);
System.out.println("------------------------");
printDetails(userTwo);
ctx.registerShutdownHook();
}
private static void printDetails(Object obj) throws Exception {
System.out.println("Is LoginTracker type :"+LoginTracker.class.isAssignableFrom(obj.getClass()));
System.out.println("Is UserService type :"+UserService.class.isAssignableFrom(obj.getClass()));
System.out.println("Implemented Interfaces : ");
for (Class clazz : obj.getClass().getInterfaces()) {
System.out.println(clazz);
}
System.out.println("Methods : ");
for (Method method : obj.getClass().getMethods()) {
System.out.println(method);
}
System.out.println("Fields : ");
for (Field field : obj.getClass().getFields()) {
System.out.println(field);
}
// If Advised
if (Advised.class.isAssignableFrom(obj.getClass())) {
LoginTracker us = (LoginTracker) obj;
System.out.println(us.incrementLoginCount());
}
}
}

打印以下日志(注意:此处仅复制日志的相关部分,以便于参考。(

rg.test.aop.two.UserServiceTwoImpl@c15d8b
------------------------
Is LoginTracker type :false
Is UserService type :true
Implemented Interfaces : 
interface rg.test.aop.UserService
Methods : 
public void rg.test.aop.one.UserServiceOneImpl.sayHello()
Fields : 
------------------------
Is LoginTracker type :true
Is UserService type :true
Implemented Interfaces : 
interface rg.test.aop.UserService
interface rg.test.aop.intro.LoginTracker
interface org.springframework.aop.SpringProxy
interface org.springframework.aop.framework.Advised
interface org.springframework.core.DecoratingProxy
Methods : 
public final java.lang.Integer com.sun.proxy.$Proxy19.incrementLoginCount()
public final void com.sun.proxy.$Proxy19.sayHello()
Fields : 
public static final java.lang.String rg.test.aop.intro.LoginTracker.FIELD
Count :6

日志显示了为UserServiceTwoImpl bean引入的方法和字段。

最新更新