spring动态添加bean

不知道大家想过没有,我们使用mybatis的时候只要写接口和配置上一个sql语句就可以了,单从代码的角度来看,这是不合理的。

所以我们通常在service里面注入的mapper它其实是一个代理对象

回到本人上一篇博客spring给容器中注入组件的几种方式

1.包扫描+组件注解标签注解

这种方式一般适用于自己写的类,动态代理的类无法添加(就算你自己动态生成的类上有注解标签,spring也无法扫描)

2.@bean

这种方式适用于加入第三方库中的类

这种方式真的可以吗?仔细想想,这种方式只能一个一个添加,像mybatis有这么多的mapper我们一个一个的加就麻烦了

3.@improt

这种方式的简单用法是肯定不行的,因为是动态生成的类,你无法再类写@improt(xxxx.class)

4.使用spring提供的factoryBean

写一个类实现factoryBean接口,重写getObject方法

这种方式显然和@bean有一样的缺陷,返回值只能有一个,还是要一个一个添加

======================================主文来了=======================================

解决办法就是@improt>>>>实现ImportBeanDefinitionRegistrar接口+.使用spring提供的factoryBean

public class MyMapperFactoryBean implements FactoryBean{

    @Autowired
    private SqlSessionFactoryBean sqlSessionFactoryBean;
    private Class aClass;

    public void setaClass(Class aClass) {
        this.aClass = aClass;
    }

    public MyMapperFactoryBean(Class aClass) {
        this.aClass = aClass;
    }
    //产生动态代理,需要产生代理的类型在构造方法传入
    @Nullable
    @Override
    public Object getObject() throws Exception {
        Class[] clazz=new Class[]{aClass};
        Object obj = Proxy.newProxyInstance(this.getClass().getClassLoader(), clazz, new MapperInvocationHandler(sqlSessionFactoryBean));
        return obj;
    }

    @Nullable
    @Override
    public Class<?> getObjectType() {
        return TestMapper.class;
    }
}
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar{
    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        //注册MyMapperFactoryBean
        //为什么不用其他方式注册MyMapperFactoryBean呢    因为这里是代码形式,可以循环,产生多个
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(MyMapperFactoryBean.class);
        AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        //传入MyMapperFactoryBean的构造方法类型  你要代理那个类就传入那个类 
        beanDefinition.getConstructorArgumentValues().addGenericArgumentValue("com.tjx.mapper.TestMapper");
        //注册
        beanDefinitionRegistry.registerBeanDefinition("mapper",beanDefinition);
    }
}

=============================这样就OK了,讲讲思路==================================

1.循环注册

2.FactoryBean这个类被我们注册到了容器中,所有可以使用spring容器中的组件  如sqlsessionFactoryBean

    //这里因为我们没有使用mybatis为我们生成动态代理 所以这里不能使用mybatis的功能
    //但是mybatis官方他自己把sqlSessionFactoryBean传入进来就是能用的 (这里有点绕,因为我不可能去把mybatis的底层实现自己写一遍)
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String str=method.getAnnotation(Select.class).value()[0];  //获取方法注解上的sql语句
        System.out.println("查询数据库"+str);
        List<Test> lists=new ArrayList<>();
        Connection con=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        int count=0;
        try {
            con=DBHelper.getCon();
            ps=con.prepareStatement(str);
            rs=ps.executeQuery();
            while (rs.next()){
                Test test=new Test();
                int id = rs.getInt("id");
                String name = rs.getString("name");
                test.setId(id);
                test.setName(name);
                lists.add(test);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        finally{
            DBHelper.myClose(con, ps, rs);
        }
//        SqlSessionFactory object = sqlSessionFactoryBean.getObject();
//        SqlSession sqlSession = object.openSession();
//        System.out.println(sqlSession);
//        List<Test> objects = sqlSession.selectList(str);
        return lists;
    }
原文地址:https://www.cnblogs.com/MonsterJ/p/12518647.html