通过反射获取Spring中的bean

继续上一篇的mybatis的分页插件。
我尝试了一下,不管怎么配置mybatis.xml文件都会导致spring不能正确的将我的插件类加载到内存中并且添加到configuration的插件链中。所以果断的放弃了使用xml配置的想法。
一维我之前也写过从ioc-di-dop-url映射的一整套流程,所以我知道那个放置bean的地方一定是可以获取的。
所以我知道其大致的流程:
首先第一种方法,请各位移步这里:

https://www.jianshu.com/p/9aa9df030109

这位博主将的很好,我就不献丑了我试试分析一下。
文章中说的实现ApplicationContextAware接口即可。
那么具体是在哪里被实例化的呢?
首先在AbstractApplicationContext中的refresh方法中的this.prepareBeanFactory(beanFactory)函数里有详解。
在这里插入图片描述还是同一个类的方法:
在这里插入图片描述
画红色的部分就是了。
在这里插入图片描述
可以看到当前的这里set中有9个元素:
在这里插入图片描述
具体的实例化笔者没有找到,感兴趣的读者可以去找下。

好了现在来说下我的方法了,不需要配置,不需要实现任何接口就可以实现想要的功能了。可以将整个的DefaultListableBeanFactory拿到(如果雷同纯属巧合),这个是我在讨厌mybatis的插件的配置失败情况下的产物吧!
还是那个refresh的函数:
在这里插入图片描述
从上图可以知道了所有的信息都是放在了这个defaultlistableBeanFactory中的。
所以只要拿到了这个就可以了。为什么挑选这个类呢?
1.在程序的运转中这个类是直接被用到的,且他也是确确实实的承载着bean信息的类。
2.选择它是有一个好处的,就是它自带了一个static的变量,恰巧这个变量的内置类型还是defaultlistableBeanFactory的,所以这样就可以非常轻松的拿取到所需要的数据了。
3.java对于静态属性的变量有一个特性,就是通过反射拿去具体的值时不需要具体的实例,其实也很好理解,应为这哥变量是类的,所以不需要实例,如果有不懂的同学,可以去看下类的加载过程就可以了。
附图:
在这里插入图片描述
所以开整了!

//这个是我的一个service层的一个函数
public UserVo findall() throws Exception {
		//拿取到DefaultListableBeanFactory类的class文件
        Class<DefaultListableBeanFactory> defaultListableBeanFactoryClass = DefaultListableBeanFactory.class;
        //拿取具体的变量,即上图中被圈出来的那个static变量
        Field serializableFactories = defaultListableBeanFactoryClass.getDeclaredField("serializableFactories");
        //设置权限
        serializableFactories.setAccessible(true);
        //拿取到具体的属性
        Map<String, Reference<DefaultListableBeanFactory>> o = (Map<String, Reference<DefaultListableBeanFactory>>)serializableFactories.get(null);
        //拿取值的set集合
        Set<Map.Entry<String, Reference<DefaultListableBeanFactory>>> entries = o.entrySet();
       
        Iterator<Map.Entry<String, Reference<DefaultListableBeanFactory>>> iterator = entries.iterator();
        //遍历iterator
        while (iterator.hasNext()){
        	//拿取元素
            Map.Entry<String, Reference<DefaultListableBeanFactory>> next = iterator.next();
         	
            System.out.println(next.getKey()+"   "+next.getValue());
            //拿取Reference值
            Reference<DefaultListableBeanFactory> value = next.getValue();
            //拿取Reference中的value,也就是DefaultListableBeanFactory 
            //至此已经拿到了想要的数据了
            DefaultListableBeanFactory defaultListableBeanFactory = value.get();
            assert defaultListableBeanFactory != null;
            //通过getBean(String beanname)获取具体的bean
            //sqlSessionFactory就是在dao的配置文件里配置的用于管理session的
            SqlSessionFactory sqlSessionFactory = (SqlSessionFactory)defaultListableBeanFactory.getBean("sqlSessionFactory");
            //拿取configuration,终于拿到了,不容易啊,这个才是最想拿到的
            Configuration configuration = sqlSessionFactory.getConfiguration();
            //添加自定义的插件,至此自定义的插件已经被加入了
            configuration.addInterceptor(new testInterceptor());
        }
        UserVo vo = new UserVo();
        vo.setUser(ud.queryall());
        return vo;
    }

在这里插入图片描述
在这里插入图片描述
附上我的简单的插件:

具体的插件装载初始化到使用,在上一篇文章中都已分析了,这里不再赘述。
@Intercepts( {
        @Signature(method = "prepare", type=StatementHandler.class, args = {Connection.class,Integer.class}) })
public class testInterceptor implements Interceptor {
    String prop1;
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("");
        StatementHandler target = (StatementHandler)invocation.getTarget();
        BoundSql boundSql = target.getBoundSql();
        String sql = boundSql.getSql();
        System.out.println(sql);
        sql+=" limit 0,10";
        Class<? extends BoundSql> aClass = boundSql.getClass();
        Field sql1 = aClass.getDeclaredField("sql");
        sql1.setAccessible(true);
        sql1.set(boundSql,sql);
        System.out.println(boundSql.getSql());
        System.out.println("///");
//        this.notifyAll();
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object o) {
        return Plugin.wrap(o,this);
    }

    @Override
    public void setProperties(Properties properties) {
        prop1 = properties.getProperty("prop1");
    }
}

来看下效果吧:
在这里插入图片描述
在这里插入图片描述
从图中的效果发现已经成功了,成功地将读取所有的元素改成了只读取前10个。

但是这个有一个缺点,虽然说这个缺点还没有暴露出来就是在DefaultListableBeanFactory的那个静态变量是一个弱引用,也就是在下一次gc的时候回被回收,所以如果是在gc回收之后再去获取那么就有可能获取不到这个变量的值。
但是如果在程序启动后就去获取,那么就可以获取到,因为不可能ssm项目刚启动就开始了gc。如果开启了gc,那么只能说你的jvm的堆和栈的配置太小了,或者说你的不是jdk1.8,应为1.8之前都是有一个永久代的。方法区就在这里,所以会出现这种情况,但是1.8后将类的元数据放到了直接内存中。所以如果还是出现了gc,那么 只能说你的内存整的太小了,或者说你开了太多的东西,留给jvm的空间不够。
所以一般情况下都是能够获取的。

为什么不挑选第一种方案呢?只能说我就是应为配置mybatis的配置文件失败的:
我寻思和网上的一毛一样啊,为什么,总是获取不到具体的插件呢?

<?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE configuration
                PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
                "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <plugins>
        <plugin interceptor="com.test.testInterceptor">
            <property name="prop1" value="prop1"/>
        </plugin>
    </plugins>
</configuration>

失败了很多次后对于配置文件彻底丧失了信心,所以只能投机取巧了。
但是我的这个办法不失为一种好的办法(哈哈哈,自恋一下)。

如转载,请说明出处!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值