范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

Spring整合Mybatis一文讲透,手把手带你实操

  在介绍Spring整合Mybatis原理之前,我们得先来稍微介绍Mybatis的工作原理。Mybatis的基本工作原理
  在Mybatis中,我们可以使用一个接口去定义要执行sql,简化代码如下: 定义一个接口,@Select表示要执行查询sql语句。1 public interface UserMapper {  2 @Select("select * from user where id = #{id}")  3 User selectById(Integer id); 4 } 复制代码
  以下为执行sql代码:1 InputStream inputStream = Resources.getResourceAsStream("mybatis.xml" );  2 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder(). build(inputStream); 3 SqlSession sqlSession = sqlSessionFactory.openSession();  4 5 // 以下使我们需要关注的重点  6 UserMapper mapper = sqlSession.getMapper(UserMapper.class);  7 Integer id = 1;  8 User user = mapper.selectById(id); 复制代码
  Mybatis的目的是:使得程序员能够以调用方法的方式执行某个指定的sql,将执行sql的底层逻辑进行了封装。 这里重点思考以下mapper这个对象,当调用SqlSession的getMapper方法时,会对传入的接口生成一个 代理对象,而程序要真正用到的就是这个代理对象,在调用代理对象的方法时,Mybatis会取出该方法所对应的sql语句,然后利用JDBC去执行sql语句,最终得到结果。分析需要解决的问题
  Spring和Mybatis时,我们重点要关注的就是这个代理对象。因为整合的目的就是:把某个Mapper的代理 对象作为一个bean放入Spring容器中,使得能够像使用一个普通bean一样去使用这个代理对象,比如能 被@Autowire自动注入。 比如当Spring和Mybatis整合之后,我们就可以使用如下的代码来使用Mybatis中的代理对象了:1 @Component  2 public class UserService {  3 @Autowired  4 private UserMapper userMapper;  5 6 public User getUserById(Integer id) {  7 return userMapper.selectById(id);  8 }  9 } 复制代码
  UserService中的userMapper属性就会被自动注入为Mybatis中的代理对象。如果你基于一个已经完成整合的项目去调试即可发现,userMapper的类型为: org.apache.ibatis.binding.MapperProxy@41a0aa7d。证明确实是Mybatis中的代理对象。 好,那么现在我们要解决的问题的就是:如何能够把Mybatis的代理对象作为一个bean放入Spring容器中?要解决这个,我们需要对Spring的bean生成过程有一个了解。Spring中Bean的产生过程
  Spring启动过程中,大致会经过如下步骤去生成bean扫描指定的包路径下的class文件根据class信息生成对应的BeanDefinition在此处,程序员可以利用某些机制去修改BeanDefinition根据BeanDefinition生成bean实例把生成的bean实例放入Spring容器中
  假设有一个A类,假设有如下代码: 一个A类1 @Component  2 public class A {   3 } 复制代码
  一个B类,不存在@Component注解1 public class B {  2 } 复制代码
  执行如下代码:1 AnnotationConfigApplicationContext context = new AnnotationConfigAppl icationContext(AppConfig.class);  2 System.out.println(context.getBean("a")); 复制代码
  输出结果为:com.luban.util.A@6acdbdf5 A类对应的bean对象类型仍然为A类。但是这个结论是不确定的,我们可以利用BeanFactory后置处理器来 修改BeanDefinition,我们添加一个BeanFactory后置处理器:1 @Component  2 public class LubanBeanFactoryPostProcessor implements BeanFactoryPost Processor {  3 @Override  4 public void postProcessBeanFactory(ConfigurableListableBeanFactor y beanFactory)  throws BeansException {  5 BeanDefinition beanDefinition = beanFactory.getBeanDefinition  ("a");  6 beanDefinition.setBeanClassName(B.class.getName());  7 }  8 } 复制代码
  这样就会导致,原本的A类对应的BeanDefiniton被修改了,被修改成了B类,那么后续正常生成的bean对 象的类型就是B类。此时,调用如下代码会报错:1 context.getBean(A.class); 复制代码
  但是调用如下代码不会报错,尽管B类上没有@Component注解:1 context.getBean(B.class); 复制代码
  并且,下面代码返回的结果是:com.luban.util.B@4b1c1ea01 AnnotationConfigApplicationContext context = new AnnotationConfigAppl icationContext(AppConfig.class);  2 System.out.println(context.getBean("a")); 复制代码
  之所以讲这个问题,是想说明 个问题:在Spring中,bean对象跟class没有直接关系,跟 BeanDefinition才有直接关系。 那么回到我们要解决的问题:如何能够把Mybatis的代理对象作为一个bean放入Spring容器中? 在Spring中,如果你想生成一个bean,那么得先生成一个BeanDefinition,就像你想new一个对象实 例,得先有一个class。解决问题
  继续回到我们的问题,我们现在想自己生成一个bean,那么得先生成一个BeanDefinition,只要有了 BeanDefinition,通过在BeanDefinition中设置bean对象的类型,然后把BeanDefinition添加给 Spring,Spring就会根据BeanDefinition 动帮我们 成 个类型对应的bean对象。 所以,现在我们要解决两个问题:Mybatis的代理对象的类型是什么?因为我们要设置给BeanDefinition我们怎么把BeanDefinition添加给Spring容器?
  注意:上文中我们使用的BeanFactory后置处理器,他只能修改BeanDefinition,并不能新增一个 BeanDefinition。我们应该使用Import技术来添加一个BeanDefinition。后面再详细介绍如果使用Import 技术来添加一个BeanDefinition,可以先看一下伪代码实现思路。
  假设:我们有一个UserMapper接口,他的代理对象的类型为UserMapperProxy。 那么我们的思路就是这样的,伪代码如下:1 BeanDefinitoin bd = new BeanDefinitoin(); 2 bd.setBeanClassName(UserMapperProxy.class.getName());  3 SpringContainer.addBd(bd); 复制代码
  但是,这里有一个严重的问题,就是上文中的UserMapperProxy是我们假设的,他表示一个代理类的类 型,然而Mybatis中的代理对象是利用的JDK的动态代理技术实现的,也就是代理对象的代理类是动态生成的,我们根本方法确定代理对象的代理类到底是什么。 所以回到我们的问题:Mybatis的代理对象的类型是什么? 本来可以有两个答案: 1. 代理对象对应的代理类 2. 代理对象对应的接口 那么答案1就相当于没有了,因为是代理类是动态生成的,那么我们来看答案2:代理对象对应的接口如果我们采用答案2,那么我们的思路就是:1 BeanDefinition bd = new BeanDefinitoin();  2 // 注意这 ,设置的是UserMapper  3 bd.setBeanClassName(UserMapper.class.getName());  4 SpringContainer.addBd(bd); 复制代码
  但是,实际上给BeanDefinition对应的类型设置为一个接口是行不通的,因为Spring没有办法根据这个 BeanDefinition去new出对应类型的实例,接口是没法直接new出实例的。 那么现在问题来了,我要解决的问题:Mybatis的代理对象的类型是什么? 两个答案都被我们否定了,所以这个问题是无解的,所以我们不能再沿着这个思路去思考了,只能回到最 开始的问题:如何能够把Mybatis的代理对象作为一个bean放入Spring容器中?
  总结上文的推理:我们想通过设置BeanDefinition的class类型,然后由Spring自动的帮助我们去生成对应的bean,但是这条路是行不通的。 终极解决方案 那么我们还有没有其他办法,可以去生成bean呢?并且生成bean的逻辑不能由Spring来帮我们做了,得 由我们自己来做。 FactoryBean 有,那就是Spring中的FactoryBean。我们可以利用FactoryBean去自定义我们要生成的bean对象,比如1 @Component 2 public class LubanFactoryBean implements FactoryBean {  3 @Override  4 public Object getObject() throws Exception {  5 Object proxyInstance = Proxy.newProxyInstance(LubanFactoryBe an.class. getClassLoader(), new Class[]{UserMapper.class}, new Invoca tionHandler() {  6 @Override  7 public Object invoke(Object proxy, Method method, Object [] args) throws Throwable {  8 if (Object.class.equals(method.getDeclaringClass())) {  9 return method.invoke(this, args);  10 } else {  11 // 执 代理逻辑  12 return null;  13 }  14 }  15 });  16 17 return proxyInstance;  18 }  19 20 @Override  21 public Class<?> getObjectType() {  22 return UserMapper.class; 23 }  24 } 复制代码
  我们定义了一个LubanFactoryBean,它实现了FactoryBean,getObject方法就是用来自定义生成bean 对象逻辑的。 执行如下代码:1 public class Test {  2 public static void main(String[] args) {  3 AnnotationConfigApplicationContext  context = new AnnotationCo nfigApplicationContext(AppConfig.class);  4 System.out.println("lubanFactoryBean: " + context.getBean ("lu banFactoryBean"));  5 System.out.println("&lubanFactoryBean: " + context.getBean ("& lubanFactoryBean"));  6 System.out.println("lubanFactoryBean-class: " +  context.getBe an("lubanFactoryBean").getClass());  7 }  8 } 复制代码
  将打印: lubanFactoryBean: com.luban.util.LubanFactoryBean1@4d41cee &lubanFactoryBean: com.luban.util.LubanFactoryBean@3712b94 lubanFactoryBean-class: class com.sun.proxy. Proxy20 从结果我们可以看到,从Spring容器中拿名字为"lubanFactoryBean"的bean对象,就是我们所自定义的 jdk动态代理所生成的代理对象。
  所以,我们可以通过FactoryBean来向Spring容器中添加一个自定义的bean对象。上文中所定义的 LubanFactoryBean对应的就是UserMapper,表示我们定义了一个LubanFactoryBean,相当于把 UserMapper对应的代理对象作为一个bean放入到了容器中。 但是作为程序员,我们不可能每定义了一个Mapper,还得去定义一个LubanFactoryBean,这是很麻烦的 事情,我们改造一下LubanFactoryBean,让他变得更通用,比如:1 @Component  2 public class LubanFactoryBean implements FactoryBean {  3 4 // 注意这里  5 private Class mapperInterface; 6 public LubanFactoryBean(Class mapperInterface) {  7 this.mapperInterface = mapperInterface;  8 }  9 10 @Override  11 public Object getObject() throws Exception {  12 Object proxyInstance = Proxy.newProxyInstance(LubanFactoryBe an.class.getClassLoader(),  new Class[]{mapperInterface}, new Invocat ionHandler() {  13 @Override  14 public Object invoke(Object proxy, Method method, Object [] args) throws Throwable {  15 16 if (Object.class.equals(method.getDeclaringClass())) {  17 return method.invoke(this, args);  18 } else {  19 // 执行代理逻辑  20 return null;  21 }  22 }  23 });  24 25 return proxyInstance;  26 }  27 28 @Override  29 public Class<?> getObjectType() {  30 return mapperInterface;  31 } 32 } 复制代码
  改造LubanFactoryBean之后,LubanFactoryBean变得灵活了,可以在构造LubanFactoryBean时,通 过构造传入不同的Mapper接口。 实际上LubanFactoryBean也是一个Bean,我们也可以通过生成一个BeanDefinition来生成一个 LubanFactoryBean,并给构造方法的参数设置不同的值,比如伪代码如下:1 BeanDefinition bd = new BeanDefinitoin(); 2 // 注意一:设置的是LubanFactoryBean  3 bd.setBeanClassName(LubanFactoryBean.class.getName());  4 // 注意二:表示当前BeanDefinition在生成bean对象时,会通过调用LubanFactoryBean  的构造方法来生成,并传入UserMapper  5 bd.getConstructorArgumentValues().addGenericArgumentValue(UserMapper. class.getName())  6 SpringContainer.addBd(bd) 复制代码
  特别说一下注意二,表示表示当前BeanDefinition在生成bean对象时,会通过调用LubanFactoryBean的 构造方法来生成,并传入UserMapper的Class对象。那么在生成LubanFactoryBean时就会生成一个 UserMapper接口对应的代理对象作为bean了。 到此为止,其实就完成了我们要解决的问题:把Mybatis中的代理对象作为一个bean放入Spring容器中。
  只是我们这是用简单的JDK代理对象模拟的Mybatis中的代理对象,如果有时间,我们完全可以调  Mybatis中提供的方法区生成一个代理对象。这里就不花时间去介绍了。 Import 到这里,我们还有一个事情没有做,就是怎么真正的定义一个BeanDefinition,并把它添加到Spring中, 上文说到我们要利用Import技术,比如可以这么实现: 定义如下类:1 public class LubanImportBeanDefinitionRegistrar implements ImportBea nDefinitionRegistrar {  2 3 @Override  4 public void registerBeanDefinitions(AnnotationMetadata importing  ClassMetadata, BeanDefinitionRegistry registry) {  5 BeanDefinitionBuilder builder = BeanDefinitionBuilder.generi cBeanDefinition();  6 AbstractBeanDefinition beanDefinition = builder.getBeanDefin ition();  7 beanDefinition.setBeanClass(LubanFactoryBean.class);  8 beanDefinition.getConstructorArgumentValues().addGenericArgu mentValue(UserMapper.class); 9 // 添加beanDefinition  10 registry.registerBeanDefinition("luban"+UserMapper.class.get SimpleName(),  beanDefinition);  11 }  12 } 复制代码
  并且在AppConfig上添加@Import注解:1 @Import(LubanImportBeanDefinitionRegistrar.class)  2 public class AppConfig { 复制代码
  这样在启动Spring时就会新增一个BeanDefinition,该BeanDefinition会生成一个LubanFactoryBean对 象,并且在生成LubanFactoryBean对象时会传入UserMapper.class对象,通过LubanFactoryBean内部 的逻辑,相当于会自动生产一个UserMapper接口的代理对象作为一个bean。总结
  总结一下,通过我们的分析,我们要整合Spring和Mybatis,需要我们做的事情如下:定义一个LubanFactoryBean定义一个LubanImportBeanDefinitionRegistrar在AppConfig上添加一个注解@Import(LubanImportBeanDefinitionRegistrar.class)
  作者:程序员周瑜
  链接:https://juejin.cn/post/7089023062800236552

餐饮娱乐公司DaveampampampBusterampamp39s视觉形象升级DaveBusters成立于1982年,是美国一家连锁娱乐和餐饮场所,从问世的那一刻起,品牌秉持着提供吃喝玩乐一条龙服务的精神,店内设置了餐饮娱乐和观影的全方位体验,是迄今为止全美售价12。98万元起,184马力比思域还强,威朗ProProGS值得买吗?紧凑级轿车市场一直都是各大车企必争的红海之地,各大主机厂也是不断革新升级自家产品终端,来提高综合竞争力。思域历经换代变得越来越商务传统,有点小雅阁的味道别克品牌也推出了威朗ProP探索高保真评测FocalChora800系列多声道系统总说周知,如果能在天花上装全景声喇叭,家庭影院的效果表现能更上一层楼,但实行起来并不容易。而Focal的Chora826D落地喇叭,直接在顶部搭载了DolbyAtmosEnable宠物食品公司PetPlate视觉形象升级PetPlate创办于2016年,是美国纽约一家为宠物提供定制餐食的公司,直接面向消费者订阅,其个性化餐食由兽医营养师根据宠物的饮食进行均衡。自成立以来,该公司已为全美的狗狗提供了食品连锁餐厅LilSweetChick视觉形象升级SweetChick创办于2013年,是美国一家小型的食品连锁餐厅,在纽约有四家门店,在洛杉矶有一家门店。最近,因新冠肺炎的关系,他们将现有的SweetChick门店转换为LilS英国线上电器零售商AO视觉形象升级AO成立于2000年,最初名为AppliancesOnline,后来称为AO。com(现在简称为AO),是英国一家专门从事家用电器的线上零售商。总部位于曼彻斯特的博尔顿,目前,仅在宠物营养补充剂Finn视觉形象设计Finn创办于2020年,致力于将研究与现代健康结合在一起,为宠物提供优质的营养补充剂。该公司最初提供的产品包括四种补充剂,旨在帮助狗狗在生活的各个阶段遇到的常见问题髋关节补充剂镇欧洲手球联合会EHF视觉形象升级欧洲手球联合会(EHF)成立于1991年,是欧洲手球运动最受欢迎的管理机构,总部位于奥地利维也纳,主要职责是组织和管理具有竞争力的手球运动比赛,拥有50个国家的成员联合会和两个相关GS套件更显运动,2。0T9AT动力组合,昂科威SGS成都展首发亮相本次成都国际车展新车亮相是应接不暇,各大厂商争相推出旗下全新或者改款车型,让消费者的选择更加丰富,同时也满足了日益增长的市场消费需求。别克品牌展台此次昂科威SGS的亮相吸引不少围观思域劲敌,动力已赢一半!满油能跑739km,破百7。7S,实拍威朗Pro都说国人富起来了,越来越多的家庭都逐步标配一台代步车,富裕大户甚至拥有多台。对于普通上班族来说,15万左右是大多数买车用户的预算范围,紧凑级轿车自然也都成为了很多人的首选。我们今天廉价航空公司VivaAir视觉形象升级VivaAir是一家廉价航空公司,由爱尔兰航空发展公司创立,迄今为止,爱尔兰航空发展公司已在全球范围内成功创建了6家廉价航空公司。早些时候,他们推出了由哥伦比亚波哥大SmartBr
新机OPPOK10如何?作为一名K9的资深用户,当然是非常看好K10的,选择K系列是因为他出色的性价比,而且K系列的外观也是很富有科技感的这次K10延续了K9Pro的外观,不同的是K10这次采用了磨砂工艺好的笔记本支架,不只是为了舒适你也会经常感到乏累吧?在我们的日常办公中,久坐成为了一种常态,但这对我们的身体来说可并不是何种福音。对于长期处于在办公室场景下的人群,由于久坐与各种姿势的不正确,身体其实长期都处于传音发布2021年财报日均赚1071万手机出货1。97亿部手机中国新闻4月27日,手机中国了解到,深圳传音控股股份有限公司发布了2021年年报。2021年,传音控股手机出货量达1。97亿部,同比增长13。07。净资产140。23亿元,同比Canalys2021年全球可穿戴腕带设备出货量同比增长4。3,苹果位列全球第一36氪获悉,Canalys最新数据显示,2021年全球可穿戴腕带设备出货量达1。93亿台,同比增长4。3。其中,苹果以11。8的增长率和超3900万台出货量位列全球第一小米因在更多中兴新机创新非常大胆,高端市场有望?三星当发贺电过去一年,手机市场依旧打得不可开交,而作为高调回归的中兴手机,目前并没有在这场战事中成为焦点。先前借助首发屏下摄像,中兴手机的确吸引了一部分目光,同时中兴努比亚红魔三箭齐发更是摆足个人信息收集新标无单独同意,不应分析相册中生物识别信息App收集用户个人信息时,过度收集个人信息不授权不给用反复索权等问题长期存在。对于此类问题,信息安全技术移动互联网应用程序(App)收集个人信息基本要求(以下简称要求)作出了回应。对标世界一流央企加速奔跑有研集团打造有色金属新材料国家战略科技力量有研科技集团有限公司(以下简称有研集团)坚持四个面向,以对标世界一流管理提升行动为契机,深化创新驱动高质量发展战略,强化科技创新体系建设,提升自主创新能力,努力打造有色金属新材料国全塑料机身黑白屏幕,内置一款游戏玩转童年,这款游戏机很经典拒绝参数,只谈体验,关注导盲犬小抠,真实解读您熟悉的数码产品,本文阅读预计耗时3分钟。游戏机是童年最亮眼的玩具,基本上所有80后90后的童年都有它的身影。对很多90后来说,童年里有QQ堂的崛起,进击的腾讯游戏如今大多已经生儿育女在中年或临近中年危机的日子里惶惶不可终日的老玩家们,在QQ堂即将停服前久违地打开了游戏,为此可能还要打开一台仍装着win7或winXP系统的旧电脑。大费周章,为游戏版号恢复发放后,还有一个好消息4月11日晚间,国家新闻出版署官网公布了2022年4月国产网络游戏审批情况共计45款游戏获得新版号,审批时间为4月8日。国家新闻出版署官网截图自2021年7月22日开始,游戏版号已自动泊车将进入AVP时代欧菲光技术突破让停车更智能在汽车智能化的浪潮中,车载传感器发展迅速,汽车搭载传感器数量也与日俱增,具备自动驾驶功能的汽车进入大众的视野。除了解决在高速环路上的开车问题,自动驾驶还可以处理令新老司机都困扰的停