反射+spring初始化工厂

需求背景:项目启动后初始化一个 url工厂,工厂中存放固定包路径下的controller中使用 自定义注解 UpperLimitAnnotation 的方法的请求 全路径;实现方式:反射+spring InitializingBean接口;

  扩展场景:初始化其他类型工厂,如 策略模式中的策略工厂等 可以结合spring  InitializingBean 实现

代码如下:

 说明:0.9.12 版本依赖  发布到  生产环境   报  org.reflections.ReflectionsException: Scanner MethodAnnotationsScanner was not configured  异常,使用0.9.11版本则无此问题;

// 反射依赖
<dependency>
            <groupId>org.reflections</groupId>
            <artifactId>reflections</artifactId>
            <version>0.9.11</version>
  </dependency>

  工厂类代码:

package com.ruijie.demo.util;

import com.alibaba.fastjson.JSON;
import com.ruijie.demo.annotaion.UpperLimitAnnotation;
import net.minidev.json.JSONUtil;
import org.assertj.core.util.Lists;
import org.reflections.Reflections;
import org.reflections.scanners.*;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

/**
 * @ClassName UrlFactory
 * @Description 对外开放接口url工厂
 * @Author WANGQW
 * @Date 2021/4/6 10:56
 **/
@Component
public class UrlFactory implements InitializingBean {

    public static final List<String> urlFactory = Lists.newArrayList();

    @Value("${spring.application.name}")
    private String applicationName;

    /**
     * @Author wangqw
     * @Description 反射获取 所有api包下所有使用UpperLimitAnnotation 的接口全路径
     * @Date 2021/4/6 15:31
     * @Param []
     * @return void
    **/
    @Override
    public void afterPropertiesSet() throws Exception {
//        Reflections reflections = new Reflections("com.ruijie.demo.api", Arrays.asList(
// new SubTypesScanner(false)//允许getAllTypes获取所有Object的子类, 不设置为false则 getAllTypes 会报错.默认为true.
// ,new MethodParameterNamesScanner()//设置方法参数名称 扫描器,否则调用getConstructorParamNames 会报错
// ,new MethodAnnotationsScanner() //设置方法注解 扫描器, 否则getConstructorsAnnotatedWith,getMethodsAnnotatedWith 会报错
// ,new MemberUsageScanner() //设置 member 扫描器,否则 getMethodUsage 会报错, 不推荐使用,有可能会报错 Caused by: java.lang.ClassCastException: javassist.bytecode.InterfaceMethodrefInfo cannot be cast to javassist.bytecode.MethodrefInfo
// ,new TypeAnnotationsScanner()//设置类注解 扫描器 ,否则 getTypesAnnotatedWith 会报错
// ));

Reflections reflections = new Reflections(new ConfigurationBuilder().setUrls(ClasspathHelper.forPackage("com.ruijie.demo.api")).setScanners(new MethodAnnotationsScanner()));

//获取所有带有 UpperLimitAnnotation 注解的方法对象 Set<Method> methods = reflections.getMethodsAnnotatedWith(UpperLimitAnnotation.class); methods.stream().forEach(item ->{ String clazzUrl = ""; RequestMapping clazzMapping = item.getDeclaringClass().getAnnotation(RequestMapping.class); if(null != clazzMapping && !ObjectUtils.isEmpty(clazzMapping.value())){ clazzUrl = clazzMapping.value()[0]; } RequestMapping methodMapping = item.getAnnotation(RequestMapping.class); if(null == methodMapping || ObjectUtils.isEmpty(methodMapping.value())){ return; } String methodUrl = methodMapping.value()[0]; String url = StringUtils.isEmpty(clazzUrl) ? "/" + applicationName + methodUrl : "/" + applicationName + clazzUrl + methodUrl; urlFactory.add(url); }); } }

  controller 中 注解使用:

package com.ruijie.demo.api;

import com.alibaba.fastjson.JSONObject;
import com.ruijie.demo.annotaion.UpperLimitAnnotation;
import com.ruijie.demo.entity.remote.RemoteOrganization;
import com.ruijie.demo.entity.remote.TycResult;
import com.ruijie.demo.service.EeterpriseApiService;
import com.ruijie.framework.common.RemoteResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

/**
 * @ClassName EnterpriseApiController
 * @Description
 * @Author WANGQW
 * @Date 2021/3/18 10:11
 **/
@RestController
@RequestMapping("/company")
public class EnterpriseApiController {

    @Autowired
    private EeterpriseApiService eeterpriseApiService;

    /**
     * @Author wangqw
     * @Description 模糊搜索企业信息-列表
     * @Date 2021/3/16 17:47
     * @Param [keyword]
     * @return com.ruijie.framework.common.RemoteResult<com.ruijie.demo.domain.remote.TycResult>
     **/
    @UpperLimitAnnotation
    @RequestMapping(value = "/search",method = RequestMethod.GET)
    public RemoteResult<TycResult> search(@RequestParam("keyword") String keyword){
        return new RemoteResult<>(eeterpriseApiService.search(keyword));
    }


}

 

简述:spring  InitializingBean 接口的作用:

1:spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中同过init-method指定,两种方式可以同时使用
2:实现InitializingBean接口是直接调用afterPropertiesSet方法,比通过反射调用init-method指定的方法效率相对来说要高点。但是init-method方式消除了对spring的依赖
3:如果调用afterPropertiesSet方法时出错,则不调用init-method指定的方法。

在spring初始化bean的时候,如果该bean是实现了InitializingBean接口,并且同时在配置文件中指定了init-method,系统则是先调用afterPropertiesSet方法,然后在调用init-method中指定的方法。

 

posted @ 2021-04-06 16:29  wl_王麟  阅读(558)  评论(0编辑  收藏  举报