zoukankan      html  css  js  c++  java
  • Mybatis 接口代理的实现(BeanDefinitionRegistryPostProcessor+FactoryBean)

    相信在开发中,尤其是mybatis 配置操作中,我们只需要提供一个mapper 接口,然后注入到service 中,就可以进行调用。

    按我们的一般逻辑来说,我们并没有进行接口的实现,应该会报空指针异常,那么Mybatis 是如何进行操作的呢?

    这主要是得于Spring 强大的扩展机制,进入正题:

    1. Spring 提供了 BeanDefinitionRegistryPostProcessor 接口,通过这个接口的实现,可以自定义一些我们bean ,让Spring 在初始化的时候进行bean 的加载

    implements BeanDefinitionRegistryPostProcessor

    2.Spring 提供了  FactoryBean的接口,源码中解释说:如果一个bean 实现了这个接口,它将会作为一个工厂对象暴露出来,而不是直接的作为一个bean 的实例

    暴露出来;反而它是用来创建bean的实例的,

    意思就是;在我们的bean 对象被spring管理后,spring在获取bean 对象时候底层调用的是getBean()方法,默认下getBean 返回的是该类的无参数构造,这一点毋庸置疑,当然还有一种就是对于实现了FactoryBean 接口的类,在spring调用 getBean()方法时候,调用的是FactoryBean 下的 getObject方法进行对象的引用创建,所以利用特性,可以进行生成接口的代理;dubbo也是如此(只不过是通过自定义标签的方式实现的)

    implements FactoryBean

    实例代码如下:

    /**
     * 实现FactoryBean 的bean,将会被作为一个对象的工厂,
     * 不会直接的作为bean 的实例暴露在外边,而是通过getObject 方法
     * 进行对象的引用,也就是说这个对象的实例是通过getObject 方法返回的
     * @author iscys
     *
     */
    public class BeanFactoryDoc implements FactoryBean {
        
        
        public static void main(String[] args) {
            ApplicationContext app = new ClassPathXmlApplicationContext("classpath:springTest/my.xml");
            
            Object bean = app.getBean("beanFactory");
            //返回的是1 ,并没有返回BeanFactoryDoc 的对象实例;
            System.out.println(bean);
        }
    
        @Override
        public Object getObject() throws Exception {
            //实际返回的对象
            return "1";
        }
    
        @Override
        public Class getObjectType() {
            //返回的对象类型
            return "1".getClass();
        }
    
        @Override
        public boolean isSingleton() {
            return true;
        }
    
        
    
    }

    ------>. 结果返回的是  1 ;而不是 BeanFactoryDoc对象,

    将第一点与第二点结合起来再加上jdk动态代理,我们就可以进行动态生成接口代理对象,并且可以进行注入的操作;

    接下来我进行模拟接口动态代理的生成:(BeanDefinitionRegistryPostProcessor  + FactoryBean + jdk proxy)

    (一).随便来个接口:

    interface TestInterface{
        
        void testMethod();
    }

    (二).实现  BeanDefinitionRegistryPostProcessor 接口主要是  postProcessBeanDefinitionRegistry, 可以使用 registry实现将自定义bean 注册到Spring中;

    /**
     * spring 通过暴露BeanDefinitionRegistryPostProcessor 接口,
     * 可以使我们在spring中加载一些我们自定义的bean,被spring 所初始化;例如
     * mybatis 接口代理对象就是通过这种方式加载进来的
     * 接下来模拟接口代理的生成方法
     * 1.知识补充,都知道,在我们的bean 对象被spring管理后,spring在获取bean 对象时候调用的是getBean()方法
     * 默认下getBean 返回的是该类的无参数构造,当然还有一种就是对于实现了FactoryBean 接口的类,在spring调用
     * getBean()方法时候,调用的是FactoryBean 下的 getObject方法所返回的对象,所以利用特性,可以进行生成接口的
     * 代理;dubbo也是如此
     * 
     * @author iscys
     *
     */
    public class BeanDefinitionRegistryDoc implements BeanDefinitionRegistryPostProcessor {
    
        
        public static void main(String[] args) {
        ApplicationContext app = new ClassPathXmlApplicationContext("classpath:springTest/my.xml");
            
        Object bean = app.getBean("testInterface");
        System.out.println(bean);
        System.out.println(bean instanceof TestInterface );
        }
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            // TODO Auto-generated method stub
            
        }
    
        /**
         * 通过这个方法将我们自定义的bean 进行加载进来
         */
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
            //bean的定义,这些都是常规的配置
            GenericBeanDefinition beanDefinition =new GenericBeanDefinition();
            //设置bean class对象交给BeanFactory 进行创建,会根据beanclass进行对象的初始化
            beanDefinition.setBeanClass(BeanFactory.class);
            //对象初始化赋值操作,给bean 的变量属性的赋值,要有属性的set方法才可以成功的赋值,底层是ArrayList
            beanDefinition.getPropertyValues().addPropertyValue("needProxyInterface", "com.baseknow.spring.TestInterface");
            //注册到bean工厂中将bean,这一步完成后Spring就可以初始化bean 对象了;
            registry.registerBeanDefinition("testInterface", beanDefinition);
        }
    
    
    
    }

    (三),要我来说,实现 FactoryBean 这个才是真正的核心哈哈,因为可以通过 getObject() 进行自定义对象的生成

    /**
     * 实现FactoryBean bean工厂
     * 不会直接的作为bean 的实例暴露在外边,而是通过getObject 方法
     * 进行对象的引用,也就是说这个对象的实例是通过getObject 方法返回的
     * @author cys
     *
     */
    class BeanFactory implements FactoryBean{
        
        //接口属性
        private Class needProxyInterface;
    
        public Class getNeedProxyInterface() {
            return needProxyInterface;
        }
      //生成set方法
        public void setNeedProxyInterface(Class needProxyInterface) {
            this.needProxyInterface = needProxyInterface;
        }
    
        @Override
        public Object getObject() throws Exception {
            System.out.println("---------getObject");
            //jdk代理,进行代理,获取代理对象,将接口传入
            return getProxy().newProxy(needProxyInterface);
        }
    
        @Override
        public Class getObjectType() {
            return this.needProxyInterface;
        }
    
        @Override
        public boolean isSingleton() {
            return true;
        }
        
        InterfaceProxy getProxy(){
            return new JdkProxy();
    }
    }

    (四).jdk 动态代理

    /**
     * JDK 动态代理模版通用方法,接口代理
     * 具体功能再进行增加
     * @author iscys
     *
     */
    public class JdkProxy implements InvocationHandler ,Serializable {
    
        private static final long serialVersionUID = -4467164789570764661L;
        
        @SuppressWarnings("unchecked")
        public /**static**/ <T> T newProxy(Class<T> myInterfaces) {
            ClassLoader classLoader = myInterfaces.getClassLoader();
            Class<?>[] interfaces =new Class[]{myInterfaces};
            //JdkProxy proxy =new JdkProxy();
            return (T) Proxy.newProxyInstance(classLoader, interfaces, this);
            
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            
            return "123";
        }
    
    }

    这样就完成了;

    测试。--> 结果是 123,   true(说明返回的对象是该接口的实现)

        public static void main(String[] args) {
        ApplicationContext app = new ClassPathXmlApplicationContext("classpath:springTest/my.xml");
            
        Object bean = app.getBean("testInterface");
        System.out.println(bean);
        System.out.println(bean instanceof TestInterface );
        }

    这样一个接口的代理就实现了,对于方法的调用需要在动态代理invoke 中下功夫;

    Mybatis 是这样的话操作的,而dubbo 则是通过自定义标签的形式进行bean 的定义初始化,接口代理,原理与这个大同小异,具体请看我的以前文章,spring自定义标签的实现;

  • 相关阅读:
    destoon去除编辑器替换图片删除原图功能,删除信息删除相关图片功能
    destoon 支付异步接口文件 notify.php 调试方式
    destoon 自定义session丢失
    MySQL中文转换成拼音的函数
    destoon ip接口失效修改 修改后偶尔会加载很慢
    destoon 多表联合查询时出现解析错误,parse_str函数解析错误
    destoon添加修改会员信息时,信息丢失
    destoon 屏蔽会员组,让个人,游客不显示
    jQuery中attr()方法用法实例
    filter 简介
  • 原文地址:https://www.cnblogs.com/iscys/p/10023831.html
Copyright © 2011-2022 走看看