栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

五丶模仿mybatis实现扫描接口进行动态代理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

五丶模仿mybatis实现扫描接口进行动态代理

本文实现扫描对应包下接口,使用JDK动态代理进行接口代理

一丶JDK动态代理的接口
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface DemoRegistry {
}


@DemoRegistry
public interface DemoBean {

    String hello();

}


public class DemoInvocationHandler implements InvocationHandler {

    public static Object build(Class type) {
        // 创建代理对象,参数分别为类加载器,需要的接口Class对应(因为代理的type就是接口,所以直接new一个class数组就行),具体的代理实现
        return Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type}, new DemoInvocationHandler());
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 自己实现对应的代理逻辑
        // 这里实现为如果方法定义的class为Object,就直接调用这个对象的方法
        if (method.getDeclaringClass() == Object.class) {
            return method.invoke(this, args);
        }
        // 方法返回值为String,就返回一个hell word,代理的具体逻辑可以自己实现
        Class returnType = method.getReturnType();
        if (returnType == String.class) {
            return "hell word";
        }
        return null;
    }
}


public class DemoFactoryBean implements FactoryBean {

    
    public final Class type;

    public DemoFactoryBean(Class type) {
        this.type = type;
    }

    @Override
    public T getObject() throws Exception {
        // 获取代理对象,使用JDK动态代理
        return (T) DemoInvocationHandler.build(type);
    }

    @Override
    public Class getObjectType() {
        // 获取对象的类型
        return type;
    }

}
二丶接口扫描及注册BeanDefinition
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
// @import注解是Spring提供的导入对应的类的注解,通过导入具体实现了importBeanDefinitionRegistrar接口的类可以自己注册BeanDefinition
@import({DemoRegistrarTest.class})
public @interface EnableDemo {

    
    String[] value();
}


public class DemoRegistrarTest implements importBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(Annotationmetadata importingClassmetadata, BeanDefinitionRegistry registry) {
        // 获取类上的EnableDemo注解的属性
        Map map = importingClassmetadata.getAnnotationAttributes(EnableDemo.class.getName());
        // 类扫描器
        MyClassScan scan = new MyClassScan(registry);
        // 从注解配置中获取扫描的包路径进行扫描
        int scanCount = scan.scan((String[]) map.get("value"));
        System.out.println(scanCount);
    }
}


public class MyClassScan extends ClassPathBeanDefinitionScanner {

    public MyClassScan(BeanDefinitionRegistry registry) {
        super(registry, false);
        // 注册筛选器
        registerFilters();
    }

    public void registerFilters() {
        // 筛选只有包含DemoRegistry注解的接口
        addIncludeFilter(new AnnotationTypeFilter(DemoRegistry.class));
    }

    
    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        // 是不是接口且是独立的bean(不依赖其他bean)
        return beanDefinition.getmetadata().isInterface() && beanDefinition.getmetadata().isIndependent();
    }

    @Override
    public Set doScan(String... basePackages) {
        // 进行扫描,获取BeanDefinitionHolder
        Set beanDefinitionHolders = super.doScan(basePackages);
        // 循环替换beanDefinition中的beanClass为FactoryBean,不进行替换的话,beanClass是接口,Spring无法通过接口得到Bean对象
        for (BeanDefinitionHolder definitionHolder : beanDefinitionHolders) {
            // 获取beanDefinition
            AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) definitionHolder.getBeanDefinition();
            // 获取扫描出的接口的beanClassName
            String beanClassName = beanDefinition.getBeanClassName();
            // 设置BeanClass为DemoFactoryBean
            beanDefinition.setBeanClass(DemoFactoryBean.class);
            // 添加构造方法的参数,DemoFactoryBean的构造方法需要Class对象,这里设置的是string的参数,spring会使用Class.forName加载
            // 成DemoFactoryBean中构造方法需要的类参数
            beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);
        }
        return beanDefinitionHolders;
    }

}
三丶测试
@Service
public class DemoInterfaceTest {

    
    @Autowired
    private DemoBean demoBean;

    @PostConstruct
    public void init() {
        // 执行方法,这里就会执行代理中的逻辑
        System.out.println(demoBean.hello());
        System.out.println(demoBean.toString());
        // 输出
        // hell word
        // com.example.cachedemo.factory.DemoInvocationHandler@30bf26df()
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/591844.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号