反射+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中指定的方法。

浙公网安备 33010602011771号