springboot2.7 java8

问题

在使用工厂模式封装service时,需要通过service的class获取其类型注解,但是有些工厂类可以取到annotation注解,有些取不到
渠道注解:

/** * xxx渠道注解 * */@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface XxxType {    /**     * 渠道的值为XxxTypeEnum枚举     */    XxxTypeEnum value();}

enum:

/** * 枚举类 */@Getter@AllArgsConstructorpublic enum XxxTypeEnum {    X1("X1", "渠道1"),    X2("X2", "渠道2");    private final String code;    private final String message;    public static XxxTypeEnum getEnumByCode(String code){        for(XxxTypeEnum value:values()){            if(StringUtils.equals(value.code, code)){                return value;            }        }        throw new CommonException("未知的XXX类型");    }}

工厂类:

@Componentpublic class XxxServiceFactory implements ApplicationContextAware {    /**     * xxx服务的映射集合     */    private static final Map SERVICE_MAP = new HashMap();    /**     * 工厂方法获取服务实现     *     * @param xxxType 渠道     * @return 服务     */    public static XxxService getService(XxxTypeEnum xxxType) {        XxxService service = SERVICE_MAP.get(xxxType);        if (service == null) {            throw new CommonException("没有匹配的服务实现类");        }        return service;    }    /**     * 初始化渠道枚举-xxx服务的映射的映射     *     * @param applicationContext 应用上下文     */    @Override    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {        Map serviceMap = applicationContext.getBeansWithAnnotation(XxxType.class);        if (ObjectUtil.isEmpty(serviceMap)) {            throw new CommonException("服务映射初始化失败");        }        serviceMap.forEach((key, bean) -> {            if (!(bean instanceof XxxService)) {                throw new CommonException("注解:" + XxxType.class + ",只能用于" + XxxService.class + "的实现类中");            }            XxxService service = (XxxService) bean;            XxxType annotation = service.getClass().getAnnotation(XxxType.class);            // annotation 有时为null            SERVICE_MAP.put(annotation.value(), service);        });    }}
public interface XxxService {    void test();    void doSomething();}

渠道1服务实现类

/** * 渠道1xxx服务实现类 */@XxxType(XxxTypeEnum.X1)@Service@Slf4jpublic class X1XxxServiceImpl implements XxxService {    @Override    public void test() {        log.info("测试渠道1 test");     }    /**     * 此方法需要事务包裹     */    @Transactional(rollbackFor = Exception.class)    @Override    public void doSomething() {        log.info("测试渠道1 do something");     }}

渠道2服务实现类

/** * 渠道1xxx服务实现类 */@XxxType(XxxTypeEnum.X2)@Service@Slf4jpublic class X2XxxServiceImpl implements XxxService {    @Override    public void test() {        log.info("测试渠道2 test");     }    @Override    public void doSomething() {        log.info("测试渠道2 do something");     }}

解决

以上为部分代码,项目启动时,显示渠道1服务实现类的annotationnull,直接npe,找了半天,发现是因为渠道1内的doSomething方法添加事务注解,因为@Transactional也是基于aop的,所以此时拿到的bean是代理对象,而代理对象的方法是不会把原来父类中的方法的注解加上去的,所以为null,所以换了种方式

... /**     * 初始化渠道枚举-xxx服务的映射的映射     *     * @param applicationContext 应用上下文     */    @Override    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {        Map serviceMap = applicationContext.getBeansWithAnnotation(XxxType.class);        if (ObjectUtil.isEmpty(serviceMap)) {            throw new CommonException("服务映射初始化失败");        }        serviceMap.forEach((key, bean) -> {            if (!(bean instanceof XxxService)) {                throw new CommonException("注解:" + XxxType.class + ",只能用于" + XxxService.class + "的实现类中");            }            // XxxService service = (XxxService) bean;            // XxxType annotation = service.getClass().getAnnotation(XxxType.class);            // SERVICE_MAP.put(annotation.value(), service);            List list = AnnotationUtil.scanClass(bean.getClass());            list.stream().filter(annotation -> annotation instanceof XxxType).findFirst().ifPresent(annotation -> {                XxxType xxxType = (XxxType) annotation;                SERVICE_MAP.put(xxxType .value(), (XxxService) bean);            });        });    }

这样就能正确的获得注解,并完成工厂类的初始化啦