@DeclareParents的作用
@DeclareParents注解是spring AOP(切面)功能提供一种组件,它可以在代理目标类上增加新的行为(新增新的方法)。可能你看到这里会有点蒙,没关系我们看下面的栗子,应该就清楚明白了。
@DeclareParents的应用demo
首先我们先通过一张图简单的理解一下,@DeclareParents注解实现的思路(注: 该图来源于《Spring in action中文版》一书,想要资料可以联系我)。
被代理的类(现有的行为-方法)
package com.swh.test.delareParents;
/**
* 现有行为方法
*/
public interface IPay {
void pay();
}
package com.swh.test.delareParents;
import org.springframework.stereotype.Component;
@Component("wechatPay")
public class WechatPay implements IPay{
@Override
public void pay() {
System.out.println("wechat pay");
}
}
代理增强类
package com.swh.test.delareParents;
/**
* 增强的行为方法
*/
public interface IPayEnhance {
void payType();
}
package com.swh.test.delareParents;
import org.springframework.stereotype.Component;
/**
* 增强类的实现
*/
@Component
public class WechatPayEnhance implements IPayEnhance{
@Override
public void payType() {
System.out.println("this pay type is wechat!");
}
}
组装类
package com.swh.test.delareParents;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class PayAspectJ {
@DeclareParents(value = "com.swh.test.delareParents.IPay+",defaultImpl = WechatPayEnhance.class)
public IPayEnhance wechatPayEnhance;
}
bean的配置类
package com.swh.test.delareParents;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan
@EnableAspectJAutoProxy
public class AnnotationConfig {
}
@EnableAspectJAutoProxy 注解的作用启用AspectJ自动代理,会为使用@Aspect注解的bean创建一个代理,如果没有这个注解,则从spring获取bean时获取的原始类,本栗子中代理的是 IPay 接口。spring在创建WechatPay 类时,会创建一个代理类。
调用者
package com.swh.test;
import com.swh.test.delareParents.IPay;
import com.swh.test.delareParents.IPayEnhance;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class TestAA {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext("com.swh.test");
IPay wechatPay = (IPay) annotationConfigApplicationContext.getBean("wechatPay");
wechatPay.pay();
IPayEnhance wechatPayEnhance = (IPayEnhance) wechatPay;
wechatPayEnhance .payType();
}
}
执行结果分析
根据执行过程中的debug可见,从spring容器中获取的wechatPay bean是一个代理对象,并且实现了两个接口,分别是IPay 和 IPayEnhance ,因此这个代理类则拥有了IPay和IPayEnhance两种接口的行为。
@DeclareParents 的结构
@DeclareParents注解由三部分组成:
- value 属性指定了哪种类型的bean要引入新的接口行为。(注:本栗子中value是IPay 并在IPay后面多了一个+,该+标识IPay下面的所有子类型,而不是IPay本身)
- defaultImpl 属性指定了新提供的行为接口的实现类。本栗子我们引入的是WechatPayEnhance类
- @DeclareParents 标注的类标识需要引入的新提供的行为接口
@DeclareParents 小结
@DecalereParents 可以为已经存在的Bean扩展新的行为方法,有的人会问为什么不直接在原始的接口中新加方法。当然这种也是可以的,但是这样做有个问题,加入原始接口下面有好多实现类,则需要对所有的实现类进行修改。这样做功能能够完成,但是从设计角度来看并不是最好的做法。况且有的时候根本没有机会修改所有的实现类,比如假如引用的原始类是第三方提供的并且没有源码。这种情况就没有办法通过直接扩展原始类来解决问题。当然还有其他的的应用场景,大家有什么不同的见解或者有不明白的地方,可以在评论区留言评论,我们一起交流。