spingboot自定义扫描器,扫描自定义注解并添加到IOC容器中

本文介绍了如何使用自定义注解在接口上标记域名和请求路径,然后通过扫描机制创建代理类,模拟FeignClient的功能。主要涉及启动类注解、接口注解、扫描类、工厂类和代理类的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.概要

本文示例是扫描接口上的自定义注解,并为接口生成相应代理类,模拟FeignClient

2.代码

2.1 启动类上注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import(HttpClientBeanDefinitionRegistrar.class)
public @interface EnableHttpClient {
}

2.2 自定义注解(用于接口上)

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HttpClient {

    String address();//域名

}

2.3自定义get请求注解

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface GetRequest {

    String value();//请求路径

}

2.4 自定义扫描类

public class HttpScanHandler extends ClassPathBeanDefinitionScanner {

    public HttpScanHandler(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
        super(registry, useDefaultFilters);
    }

    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {

        addIncludeFilter(new AnnotationTypeFilter(HttpClient.class));
        Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
        if(CollectionUtil.isNotEmpty(beanDefinitionHolders)){
            beanDefinitionHolders.forEach(beanDefinitionHolder -> {
                GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanDefinitionHolder.getBeanDefinition();
                try {
                    Class<?> aClass = Class.forName(beanDefinition.getBeanClassName());
                    String address = aClass.getAnnotation(HttpClient.class).address();
                    beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(aClass);
                    beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(address);
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
                beanDefinition.setBeanClass(HttpFactory.class);
                beanDefinition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
            });
        }
        return beanDefinitionHolders;
    }

    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
    }
}

2.5 自定义ImportBeanDefinitionRegistrar

public class HttpClientBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        HttpScanHandler scanHandle = new HttpScanHandler(beanDefinitionRegistry,false);
        scanHandle.doScan(ClassUtils.getPackageName(annotationMetadata.getClassName()));
    }

}

2.6 启动类

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableHttpClient
public class SpringRegisterApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringRegisterApplication.class, args);
    }

}

2.7 工厂类

public class HttpFactory implements FactoryBean<Object> {

    private final Class<?> interFace;

    private final String address;

    public HttpFactory(Class<?> interFace,String address) {
        this.interFace = interFace;
        this.address = address;
    }

    @Override
    public Object getObject() {
        return Proxy.newProxyInstance(interFace.getClassLoader(),new Class[]{interFace},new HttpProxyHandler(address));
    }

    @Override
    public Class<?> getObjectType() {
        return interFace;
    }
}

2.8 代理类

@Slf4j
public class HttpProxyHandler implements InvocationHandler {

    private String address;

    public HttpProxyHandler(String address) {
        this.address = address;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String query = method.getAnnotation(GetRequest.class).value();
        Map<String,String> map = new HashMap<>();
        map.put("question","1111");
        String s = HttpClient.doGet(address + query, map, null);
        return null;
    }
}

3.示例

@HttpClient(address = "http://localhost:8080")
public interface HttpInterface {

    @GetRequest("/test/getNluResult")
    void run();

}
@Slf4j
@Service
public class BeanServiceImpl implements BeanService {

    @Resource
    private HttpInterface httpInterface;

    @Override
    public void k() {
        httpInterface.run();
    }
}

简单模拟了FeignClient请求,有问题的小伙伴可以留言

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值