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

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

五丶模仿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()
    }
}

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zaji/5583038.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-12-14
下一篇2022-12-14

发表评论

登录后才能评论

评论列表(0条)

    保存