Closed john-70 closed 1 year ago
看一下用的什么版本 @Resource(type = xxx.class) 这种形式是今年1月之后的版本支持的,测试类是https://github.com/Adrninistrator/java-all-call-graph/blob/main/java-all-call-graph/src/test/java/test/call_graph/spring/bean/use/TestSpringBeanC.java
可以在java-all-call-graph项目执行gradlew test_jar
命令生成测试用的test.jar验证一下
我只使用了callgraph2,最新的1.0.8
看了下例子,目前猜测区别在于我例子中的父类是接口,你的是抽象类
@Resource(type = SpringServiceImplC2.class)
protected SpringInterfaceC springServiceC2B;
我把上面示例类里改成在接口上指定@Resource注解,还是能识别出来对应SpringServiceImplC2类的,是不是相关的class文件所在的jar包没有在配置文件里指定
我发现了真正的区别,你的SpringServiceImplC2类上的@Repository填写了value,而我仅单纯使用了@Service。我尝试将你示例中SpringServiceImplC2上@Repository删除value值"test.call_graph.spring.bean.define.SpringServiceImplC2",就复现了我的状况。
我看一下,支持一下这种情况
另外,我的尝试结果里,还有情况是未支持的。如:仅使用@Resource,未填写name或type的场景,spring正常会通过字段的name或字段声明定义的type去匹配bean。以及@Inject @Named注解。这些后续会考虑支持吗?
@Resource不指定name或者type的情况,和@Service的使用是类似的,这种情况下没有做特殊的处理,因为对应的接口一般只有一个实现类,接口的方法本身会关联到实现类对应的方法,所以可以不用把被调用字段的类型替换成实现类的类型
@Inject、@Named这些注解,如果是对字段注入,而且需要指定name的方式的话,也可以支持,构造函数和方法注入现在还没有处理
不指定name的场景,并非只有一个实现类,而是取了field的name去匹配。可以理解为将注解的name偷懒配置为注解所在field的name,如同"约定大于配置"的味道
@Autowired也有类似的体验,按照类型找到多个bean时,会注入符合字段name的bean
我看下哈,这几天有空了优化下
代码提交了,版本1.0.9
@Inject + @Named 的效果预期应该与@Autowired+@Qualifier一致,但在我的测试,2者是不一致的
@Qualifier("noService")
@Autowired
private IService nameOnlyService1;
@Named("noService")
@Inject
private IService nameOnlyService3;
private void testNameOnly1() {
nameOnlyService1.deal();
}
private void testNameOnly3() {
nameOnlyService3.deal();
}
// 实际类
@Service
public class NameFirstService implements IService {
@Override
public void deal() {
isNameFirst();
}
private void isNameFirst(){}
}
// 干扰类
@Service
public class NameOnlyService3 implements IService {
@Override
public void deal() {
isNameOnlyService3();
}
private void isNameOnlyService3(){}
}
13 org.testcase.ctrl.TestCtrl:testNameOnly1() (_SPR_ACT_I)org.testcase.service.NameOnlyService:deal() 76 f 1 1
15 org.testcase.ctrl.TestCtrl:testNameOnly3() (_SPR_ACT_I)org.testcase.service4.NameOnlyService3:deal() 84 f 1 1
@Named("noService")
@Inject
private IService nameOnlyService3;
这种写法是说有@Named及@Inject注解的时候,会优先使用@Named注解的value属性去找对应的Bean么 我晚上再优化一下
是的,和@Autowired+@qualifier一样的效果
另外 @Resource(type) 在有自定义beanName如@Service("xxService")时会失效,比较取巧的解决方式是将 DefineSpringBeanByAnnotationHandler.handleSpringComponentAnnotation() 新加的逻辑放在首行
// 修改前
private void handleSpringComponentAnnotation(AnnotationEntry annotationEntry, String className) {
// 若Component相关注解的value属性值非空,则作为Bean名称使用
String valueAttributeValue = JavaCGAnnotationUtil.getAnnotationAttributeStringValue(annotationEntry, SpringAnnotationConstants.ANNOTATION_ATTRIBUTE_VALUE);
if (StringUtils.isNotBlank(valueAttributeValue)) {
stringBeanNameAndTypeMap.put(valueAttributeValue, Collections.singletonList(className));
return;
}
// 若Component相关注解的value属性值为空
// 将类名首字母小写作为Bean名称作用
String simpleClassName = JavaCGUtil.getSimpleClassNameFromFull(className);
String firstLetterLowerClassName = JavaCGUtil.getFirstLetterLowerClassName(simpleClassName);
stringBeanNameAndTypeMap.put(firstLetterLowerClassName, Collections.singletonList(className));
// 再将类名作为Bean名称作用(用来支持Bean使用@Service、@Repository等注解定义,使用@Resource的type属性注入对应Bean)
stringBeanNameAndTypeMap.put(className, Collections.singletonList(className));
}
// 修改后
private void handleSpringComponentAnnotation(AnnotationEntry annotationEntry, String className) {
// 再将类名作为Bean名称作用(用来支持Bean使用@Service、@Repository等注解定义,使用@Resource的type属性注入对应Bean)
stringBeanNameAndTypeMap.put(className, Collections.singletonList(className));
// 若Component相关注解的value属性值非空,则作为Bean名称使用
String valueAttributeValue = JavaCGAnnotationUtil.getAnnotationAttributeStringValue(annotationEntry, SpringAnnotationConstants.ANNOTATION_ATTRIBUTE_VALUE);
if (StringUtils.isNotBlank(valueAttributeValue)) {
stringBeanNameAndTypeMap.put(valueAttributeValue, Collections.singletonList(className));
return;
}
// 若Component相关注解的value属性值为空
// 将类名首字母小写作为Bean名称作用
String simpleClassName = JavaCGUtil.getSimpleClassNameFromFull(className);
String firstLetterLowerClassName = JavaCGUtil.getFirstLetterLowerClassName(simpleClassName);
stringBeanNameAndTypeMap.put(firstLetterLowerClassName, Collections.singletonList(className));
}
更新版本了,1.0.10
上面两个问题优化了,再帮忙验证一下,感谢
已验证,已解决
该场景下,UseSpringBeanByAnnotationHandler.doGetSpringBeanName 直接将类型作为 beanName(fieldSpringBeanType变量)返回,但后续 defineSpringBeanByAnnotationHandler.getSpringBeanTypeList() 仅根据 beanName 从 stringBeanNameAndTypeMap 中获取typeList, stringBeanNameAndTypeMap中没有将type作为key的数据。此时未获取到准确的type
如: @Service public class Third1AuthService extends IAuthService { }
@Service public class Third2AuthService extends IAuthService { }
@Service public class Third3AuthService extends IAuthService { }
@Resource(type = Third1AuthService.class) private IAuthService third01AuthService;