BeanWrapper

合集下载

Java依据集合元素的属性,集合相减

Java依据集合元素的属性,集合相减

Java依据集合元素的属性,集合相减两种⽅法:1.集合相减可以使⽤阿帕奇的⼀个ListUtils.subtract(list1,list2)⽅法,这种⽅法实现必须重写集合中对象的属性的hashCode和equals⽅法,集合相减判断的会调⽤equals⽅法,这种⽅法的好处是可以重写多个属性的hashCode和equals⽅法,也就是说⽤阿帕奇集合相减⽐较多个属性的⽐较灵活多样。

带来的问题也⽐较明显,重写hashCode和equals⽅法后,在使⽤hashMap时要特别注意。

2.⾃⼰实现⼀个集合相减的⽅法。

⽤hashMap实现这种⽅法不需要重写hashCode和equals⽅法,但是只能对⼀个属性进⾏⽐较相减。

/*** 依据集合元素的属性,从list1中减去list2中存在的元素,** @param list1* @param list2* @param argumentName* @return*/public static <T> List<T> subtractList(List<T> list1, List<T> list2, String argumentName) {List<T> result = new ArrayList<T>();if (CollectionUtils.isEmpty(list1)) {return result;}if (CollectionUtils.isEmpty(list2)) {return list1;}Map<Object, T> map = initMap(list2, argumentName);for (T t : list1) {BeanWrapper beanWrapper = new BeanWrapperImpl(t);Object value = beanWrapper.getPropertyValue(argumentName);if (map.get(value) == null) {result.add(t);}}return result;}private static <T> Map<Object, T> initMap(List<T> list2, String argumentName) {Map<Object, T> resultMap = new HashMap<Object, T>(list2.size());for (T t : list2) {BeanWrapper beanWrapper = new BeanWrapperImpl(t);if (beanWrapper.getPropertyValue(argumentName) == null) {throw new RuntimeException("argumentName is null");}resultMap.put(beanWrapper.getPropertyValue(argumentName), t);}return resultMap;}依据⾃⼰的业务需求,⾃⾏选择。

java copyproperties方法

java copyproperties方法

java copyproperties方法在Java编程中,"copyProperties" 方法是一种常用的功能,它用于将一个对象中的属性值复制到另一个对象中。

这在对象之间的数据传递和对象转换时特别有用。

本文将详细解释Java中的copyProperties方法,并提供相应的使用示例。

### Java copyProperties 方法介绍`copyProperties` 方法通常在Java的BeanUtils或Spring的BeanWrapper中可以找到,其主要作用是在两个JavaBean之间复制属性。

它通过反射机制工作,可以自动识别并复制具有相同名称和兼容类型的属性。

在Spring框架中,`BeanWrapper` 接口提供了一个`copyProperties` 方法,而在Apache Commons的BeanUtils库中,也有一个同名的方法。

### 使用场景当你需要:- 在两个具有相似结构的对象间迁移数据。

- 在DTO(Data Transfer Object)和实体(Entity)之间转换数据。

- 创建对象的深拷贝。

### 示例以下是使用Spring的`BeanWrapper`和Apache Commons BeanUtils 库实现`copyProperties`的示例。

#### 使用Spring的BeanWrapper```javaimport org.springframework.beans.BeanWrapper;import org.springframework.beans.PropertyAccessorFactory;public class CopyPropertiesExample {public static void main(String[] args) {Source source = new Source();source.setName("John Doe");source.setAge(30);Destination destination = new Destination();BeanWrapper bwSource = PropertyAccessorFactory.forBeanPropertyAccess(source);BeanWrapper bwDestination = PropertyAccessorFactory.forBeanPropertyAccess(destination);bwDestination.copyProperties(bwSource);System.out.println(destination.getName()); // 输出:John DoeSystem.out.println(destination.getAge()); // 输出:30 }}class Source {private String name;private int age;// Getters and Setters}class Destination {private String name;private int age;// Getters and Setters}```#### 使用Apache Commons BeanUtils首先,需要添加BeanUtils的依赖。

Spring4.1——Spring核心部分及其他

Spring4.1——Spring核心部分及其他

Spring 4.1对核心部分没有很亮点的增强,主要还是一些改进和增强;本文将一一道来。

1、DirectFieldAccessorSpring内部大量使用BeanWrapper进行属性取值赋值(setter/getter),不过到目前为止没有简单的办法去获取对象字段值;之前都是通过ReflectionUtils获取Field然后进行操作;Spring 4.1提供了DirectFieldAccessor来完成此功能:Java代码收藏代码//嵌套设置/访问对象字段数据DirectFieldAccessor accessor = new DirectFieldAccessor(bean);//如果嵌套对象为null,字段创建accessor.setAutoGrowNestedPaths(true);//设置字段值accessor.setPropertyValue("", "zhangsan");//读取字段值System.out.println(accessor.getPropertyValue(""));在Spring MVC中也可以通过如下方式给对象字段绑定数据:Java代码收藏代码@RequestMapping("/directField")public String directFieldInject(MyUser user) {System.out.println(user);return user.toString();}@InitBinderpublic void initBinder(DataBinder dataBinder) {dataBinder.initDirectFieldAccess();//直接字段访问必须加这句才可以}2、Yaml支持YAML类似于JSON,做配置文件还是不错的,需要添加org.yaml.snakeyaml依赖。

MyBatisPlus插件机制与执行流程原理分析详解

MyBatisPlus插件机制与执行流程原理分析详解

MyBatisPlus插件机制与执⾏流程原理分析详解MyBatis Plus插件MyBatis Plus提供了分页插件PaginationInterceptor、执⾏分析插件SqlExplainInterceptor、性能分析插件PerformanceInterceptor以及乐观锁插件OptimisticLockerInterceptor。

Mybatis 通过插件 (Interceptor) 可以做到拦截四⼤对象相关⽅法的执⾏ ,根据需求完成相关数据的动态改变。

四⼤对象是:ExecutorStatementHandlerParameterHandlerResultSetHandler四⼤对象的每个对象在创建时,都会执⾏interceptorChain.pluginAll(),会经过每个插件对象的 plugin()⽅法,⽬的是为当前的四⼤对象创建代理。

代理对象就可以拦截到四⼤对象相关⽅法的执⾏,因为要执⾏四⼤对象的⽅法需要经过代理。

① xml下插件的配置如下所⽰:<bean id="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean"><!-- 数据源 --><property name="dataSource" ref="dataSource"></property><property name="configLocation" value="classpath:mybatis-config.xml"></property><!-- 别名处理 --><property name="typeAliasesPackage" value="com.jane.mp.beans"></property><!-- 注⼊全局MP策略配置 --><property name="globalConfig" ref="globalConfiguration"></property><!-- 插件注册 --><property name="plugins"><list><!-- 注册分页插件 --><bean class="com.baomidou.mybatisplus.plugins.PaginationInterceptor"></bean><!-- 注册执⾏分析插件 --><bean class="com.baomidou.mybatisplus.plugins.SqlExplainInterceptor"><property name="stopProceed" value="true"></property></bean><!-- 注册性能分析插件 --><bean class="com.baomidou.mybatisplus.plugins.PerformanceInterceptor"><property name="format" value="true"></property><!-- <property name="maxTime" value="5"></property> --></bean><!-- 注册乐观锁插件 --><bean class="com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor"></bean></list></property></bean>② springboot下注册插件这⾥以分页插件为例:@Bean public PaginationInterceptor paginationInterceptor(){PaginationInterceptor paginationInterceptor = new PaginationInterceptor();// 设置请求的页⾯⼤于最⼤页后操作, true调回到⾸页,false 继续请求默认false// paginationInterceptor.setOverflow(false);// 设置最⼤单页限制数量,默认 500 条,-1 不受限制// paginationInterceptor.setLimit(500);// 开启 count 的 join 优化,只针对部分 left joinpaginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));return paginationInterceptor;}③ SqlExplainInterceptorSQL执⾏分析拦截器,全类名是com.baomidou.mybatisplus.plugins.SqlExplainInterceptor,只⽀持 MySQL5.6.3以上版本。

Spring5核心原理与30个类手写实战pdf下载

Spring5核心原理与30个类手写实战pdf下载

Spring5核心原理与30个类手写实战pdf下载基于编程开发实践,不仅深度解析Spring 5的原理与新特性,更从环境准备、顶层结构设计、数据访问等方面一步步地推导出Spring的设计原理。

在每个知识点上,均以大量的经典代码案例辅助讲解,使理论紧密联系实际。

最后手写30个类,以体会Spring的创作过程,让每一位读者学以致用。

Spring5核心原理与30个类手写实战资料目录第1篇 Spring内功心法第1章软件架构设计原则 21.1 开闭原则 21.2 依赖倒置原则 41.3 单一职责原则 71.4 接口隔离原则 101.5 迪米特原则 121.6 里氏替换原则 141.7 合成复用原则 191.8 设计原则总结 20第2章 Spring中常用的设计模式 212.1 为什么要从设计模式开始 212.1.1 写出优雅的代码 222.1.2 更好地重构项目 242.1.3 经典框架都在用设计模式解决问题 36 2.2 工厂模式详解 362.2.1 工厂模式的由来 362.2.2 简单工厂模式 372.2.3 工厂方法模式 412.2.4 抽象工厂模式 432.2.5 利用工厂模式重构的实践案例 472.3 单例模式详解 532.3.1 单例模式的应用场景 532.3.2 饿汉式单例模式 532.3.3 懒汉式单例模式 542.3.4 反射破坏单例 602.3.5 序列化破坏单例 612.3.6 注册式单例模式 682.3.7 线程单例实现ThreadLocal 742.3.8 单例模式小结 752.4 原型模式详解 752.4.1 原型模式的应用场景 752.4.2 浅克隆 772.4.3 深克隆 792.4.4 克隆破坏单例模式 812.4.5 clone()方法的源码 822.5 代理模式详解 822.5.1 代理模式的应用场景 822.5.2 静态代理 832.5.3 动态代理 882.5.4 代理模式与Spring 1072.5.5 静态代理和动态代理的本质区别 1082.5.6 代理模式的优缺点 1092.6 委派模式详解 1092.6.1 委派模式的定义及应用场景 1092.6.2 委派模式在源码中的体现 1112.7 策略模式详解 .1142.7.1 策略模式的应用场景 1142.7.2 用策略模式实现选择支付方式的业务场景 .114 2.7.3 策略模式在JDK源码中的体现 1222.7.4 策略模式的优缺点 1252.7.5 委派模式与策略模式综合应用 1252.8 模板模式详解 1292.8.1 模板模式的应用场景 1292.8.2 利用模板模式重构JDBC操作业务场景 132 2.8.3 模板模式在源码中的体现 1362.8.4 模板模式的优缺点 1382.9 适配器模式详解1392.9.1 适配器模式的应用场景 1392.9.2 重构第三方登录自由适配的业务场景141 2.9.3 适配器模式在源码中的体现 1492.9.4 适配器模式的优缺点 1532.10 装饰者模式详解 1532.10.1 装饰者模式的应用场景 1532.10.2 装饰者模式和适配器模式对比 1632.10.3 装饰者模式在源码中的应用 1632.10.4 装饰者模式的优缺点 1652.11 观察者模式详解 1652.11.1 观察者模式的应用场景 1652.11.2 观察者模式在源码中的应用 1752.11.3 基于Guava API轻松落地观察者模式 176 2.11.4 观察者模式的优缺点 1772.12 各设计模式的总结与对比 177 2.12.1 GoF 23种设计模式简介 177 2.12.2 设计模式之间的关联关系 178 2.12.3 Spring中常用的设计模式 182 2.13 Spring中的编程思想总结 183 第2篇 Spring环境预热第3章 Spring的前世今生 1863.1 一切从Bean开始 1873.2 Spring的设计初衷 1883.3 BOP编程伊始 1883.4 理解BeanFactory 1893.5 AOP编程理念 189第4章 Spring 5系统架构 1914.1 核心容器 1924.2 AOP和设备支持1924.3 数据访问与集成1934.4 Web组件 1944.5 通信报文 1944.6 集成测试 1944.7 集成兼容 1944.8 各模块之间的依赖关系 194第5章 Spring版本命名规则 1965.1 常见软件的版本命名 1965.2 语义化版本命名通行规则 1975.3 商业软件中常见的修饰词 1975.4 软件版本号使用限定 1985.5 Spring版本命名规则 199第6章 Spring源码下载及构建技巧 2006.1 Spring 5源码下载 2006.2 基于Gradle的源码构建技巧 2016.3 Gradle构建过程中的坑 207第3篇 Spring核心原理第7章用300行代码手写提炼Spring核心原理 210 7.1 自定义配置 2107.1.1 配置application.properties文件 2107.1.2 配置web.xml文件 2107.1.3 自定义注解 2117.1.4 配置注解 2127.2 容器初始化 2137.2.1 实现1.0版本 2137.2.2 实现2.0版本 2167.2.3 实现3.0版本 2237.3 运行效果演示 227第8章一步一步手绘Spring IoC运行时序图 228 8.1 Spring核心之IoC容器初体验 2288.1.1 再谈IoC与DI 2288.1.2 Spring核心容器类图 2298.1.3 Web IoC容器初体验 2328.2 基于XML的IoC容器的初始化 2378.2.1 寻找入口 2388.2.2 获得配置路径 2388.2.3 开始启动 2408.2.4 创建容器 2428.2.5 载入配置路径 2438.2.6 分配路径处理策略 2448.2.7 解析配置文件路径 2478.2.8 开始读取配置内容 2498.2.9 准备文档对象 2508.2.10 分配解析策略 2518.2.11 将配置载入内存 2528.2.12 载入<bean>元素 2578.2.13 载入<property>元素 2618.2.14 载入<property>子元素 2648.2.15 载入<list>子元素 2668.2.16 分配注册策略 2678.2.17 向容器注册 2678.3 基于注解的IoC初始化 2708.3.1 注解的前世今生 2708.3.2 定位Bean扫描路径 2718.3.3 读取注解的元数据 2738.3.4 扫描指定包并解析为BeanDefinition 277 8.3.5 注册注解BeanDefinition 2838.4 IoC容器初始化小结 285第9章一步一步手绘Spring DI运行时序图 287 9.1 Spring自动装配之依赖注入 2879.1.1 依赖注入发生的时间 2879.1.2 寻找获取Bean的入口 2889.1.3 开始实例化 2939.1.4 选择Bean实例化策略 2979.1.5 执行Bean实例化 2999.1.6 准备依赖注入 3019.1.7 解析属性依赖注入规则 3069.1.8 注入赋值 3109.2 Spring IoC容器中那些鲜为人知的细节 314 9.2.1 关于延时加载 3149.2.2 关于FactoryBean和BeanFactory 3179.2.3 再述autowiring 322第10章一步一步手绘Spring AOP运行时序图 326 10.1 Spring AOP初体验 32610.1.1 再述Spring AOP应用场景 32610.1.2 AOP中必须明白的几个概念 32710.1.3 使用Spring AOP的两种方式 32910.1.4 切入点表达式的配置规则 33310.2 Spring AOP源码分析 33410.2.1 寻找入口 33410.2.2 选择代理策略 33810.2.3 调用代理方法 34110.2.4 触发通知 347第11章一步一步手绘Spring MVC运行时序图 352 11.1 初探Spring MVC请求处理流程 35211.2 Spring MVC九大组件 35311.2.1 HandlerMapping 35311.2.2 HandlerAdapter 35311.2.3 HandlerExceptionResolver 354 11.2.4 ViewResolver 35411.2.5 RequestToViewNameTranslator 354 11.2.6 LocaleResolver 35411.2.7 ThemeResolver 35511.2.8 MultipartResolver 35511.2.9 FlashMapManager 35511.3 Spring MVC源码分析 35511.3.1 初始化阶段 35611.3.2 运行调用阶段 35911.4 Spring MVC优化建议 367第4篇 Spring手写实战第12章环境准备 37012.1 IDEA集成Lombok插件 37012.1.1 安装插件 37012.1.2 配置注解处理器 37312.1.3 使用插件 37412.2 从Servlet到ApplicationContext 375 12.3 准备基础配置37612.3.1 application.properties配置.377 12.3.2 pom.xml配置 37712.3.3 web.xml配置 37812.3.4 GPDispatcherServlet 378第13章 IoC顶层结构设计 38013.1 Annotation(自定义配置)模块 380 13.1.1 @GPService 38013.1.2 @GPAutowired 38113.1.3 @GPController 38113.1.4 @GPRequestMapping 38213.1.5 @GPRequestParam 38213.2 core(顶层接口)模块 38213.2.1 GPFactoryBean 38213.2.2 GPBeanFactory 38313.3 beans(配置封装)模块 38313.3.1 GPBeanDefinition 38313.3.2 GPBeanWrapper 38413.4 context(IoC容器)模块 38513.4.1 GPAbstractApplicationContext 385 13.4.2 GPDefaultListableBeanFactory 385 13.4.3 GPApplicationContext38513.4.4 GPBeanDefinitionReader 38813.4.5 GPApplicationContextAware 391第14章完成DI模块的功能 39214.1 从getBean()方法开始 39314.2 GPBeanPostProcessor 395第15章完成MVC模块的功能 39615.1 MVC顶层设计 39615.1.1 GPDispatcherServlet 39615.1.2 GPHandlerMapping 40215.1.3 GPHandlerAdapter 40315.1.4 GPModelAndView 40615.1.5 GPViewResolver 40615.1.6 GPView 40715.2 业务代码实现40915.2.1 IQueryService 40915.2.2 QueryService 41015.2.3 IModifyService 41015.2.4 ModifyService 41115.2.5 MyAction 41215.2.6 PageAction 41315.3 定制模板页面41415.3.1 first.html 41415.3.2 404.html 41415.3.3 500.html 41515.4 运行效果演示415第16章完成AOP代码织入 417 16.1 基础配置 .41716.2 完成AOP顶层设计 41816.2.1 GPJoinPoint 41816.2.2 GPMethodInterceptor .419 16.2.3 GPAopConfig 41916.2.4 GPAdvisedSupport 420 16.2.5 GPAopProxy 42216.2.6 GPCglibAopProxy 42316.2.7 GPJdkDynamicAopProxy 423 16.2.8 GPMethodInvocation425 16.3 设计AOP基础实现 42716.3.1 GPAdvice 42716.3.2 GPAbstractAspectJAdvice 427 16.3.3 GPMethodBeforeAdvice 428 16.3.4 GPAfterReturningAdvice 429 16.3.5 GPAfterThrowingAdvice 430 16.3.6 接入getBean()方法 43016.4 织入业务代码43216.4.1 LogAspect 43216.4.2 IModifyService 43316.4.3 ModifyService 43416.5 运行效果演示435第5篇 Spring数据访问第17章数据库事务原理详解 438 17.1 从Spring事务配置说起 438 17.2 事务的基本概念 43917.3 事务的基本原理 43917.4 Spring事务的传播属性 440 17.5 数据库事务隔离级别 44117.6 Spring中的事务隔离级别 441 17.7 事务的嵌套 44217.8 Spring事务API架构图 44417.9 浅谈分布式事务 444第18章 Spring JDBC源码初探 44618.1 异常处理 44718.2 config模块 44818.3 core模块45018.4 DataSource 45618.5 object模块 45718.6 JdbcTemplate 45818.7 NamedParameterJdbcTemplate 458第19章基于Spring JDBC手写ORM框架 459 19.1 实现思路概述45919.1.1 从ResultSet说起 45919.1.2 为什么需要ORM框架 46419.2 搭建基础架构46719.2.1 Page 46719.2.2 ResultMsg 47019.2.3 BaseDao 47119.2.4 QueryRule 47319.2.5 Order.47919.3 基于Spring JDBC实现关键功能 480 19.3.1 ClassMappings 48019.3.2 EntityOperation 48319.3.3 QueryRuleSqlBuilder 48819.3.4 BaseDaoSupport 49819.4 动态数据源切换的底层原理 50719.4.1 DynamicDataSource 50819.4.2 DynamicDataSourceEntry 50919.5 运行效果演示51019.5.1 创建Member实体类 51019.5.2 创建Order实体类 51119.5.3 创建MemberDao 51219.5.4 创建OrderDao 51219.5.5 修改db.properties文件 51419.5.6 修改application-db.xml文件 515 19.5.7 编写测试用例 516第6篇 Spring经验分享第20章 Spring 5新特性总结 52020.1 升级到Java SE 8和Java EE 7 520 20.2 反应式编程模型 52120.3 使用注解进行编程 52120.4 函数式编程 52220.5 使用 REST 端点执行反应式编程 52320.6 支持HTTP/2 52320.7 Kotlin和Spring WebFlux 52320.8 使用Lambda表达式注册Bean 52420.9 Spring Web MVC 支持最新的 API 52420.10 使用JUnit 5执行条件和并发测试 52520.11 包清理和弃用 52620.12 Spring核心和容器的一般更新 52620.13 我如何看Spring 5 527第21章关于Spring的经典高频面试题 52821.1 什么是Spring框架,Spring框架有哪些主要模块52821.2 使用Spring框架能带来哪些好处 52821.3 什么是控制反转(IoC),什么是依赖注入 52921.4 在Java中依赖注入有哪些方式 52921.5 BeanFactory和ApplicationContext有什么区别 530 21.6 Spring提供几种配置方式来设置元数据 53021.7 如何使用XML配置方式配置Spring .53121.8 Spring提供哪些配置形式 53221.9 怎样用注解的方式配置Spring 53321.10 请解释Spring Bean的生命周期 53421.11 Spring Bean作用域的区别是什么 53521.12 什么是Spring Inner Bean 53521.13 Spring中的单例Bean是线程安全的吗 53621.14 请举例说明如何在Spring中注入一个Java集合 53621.15 如何向Spring Bean中注入java.util.Properties 53721.16 请解释Spring Bean的自动装配 53821.17 自动装配有哪些局限性 53821.18 请解释各种自动装配模式的区别 53921.19 请举例解释@Required注解 53921.20 请举例说明@Qualifier注解 54021.21 构造方法注入和设值注入有什么区别 54021.22 Spring中有哪些不同类型的事件 54121.23 和ClassPathResource有什么区别 54221.24 Spring中用到了哪些设计模式 54221.25 在Spring中如何更有效地使用JDBC 54321.26 请解释Spring中的IoC容器 54321.27 在Spring中可以注入null或空字符串吗 543Spring5核心原理与30个类手写实战介绍1996年,Java还只是一个新兴的、初出茅庐的编程语言。

java,得到entity对象的字段数量方法

java,得到entity对象的字段数量方法

java,得到entity对象的字段数量方法Java中得到Entity对象的字段数量方法方法1:使用反射机制•使用Class类的getDeclaredFields()方法获取字段数组•通过数组的长度即可得到字段数量方法2:使用Introspector•使用类的getBeanInfo()方法获取Bean的信息•通过BeanInfo类的getPropertyDescriptors()方法获取属性描述器数组•遍历数组并排除掉getClass()方法,即可得到字段数量方法3:使用Apache Commons BeanUtils•引入Apache Commons BeanUtils库•使用BeanUtils类的getPropertyDescriptors()方法获取属性描述器数组•遍历数组并排除掉getClass()方法,即可得到字段数量方法4:使用Spring的BeanWrapper•引入Spring框架•使用BeanWrapper类的getPropertyDescriptors()方法获取属性描述器数组•遍历数组并排除掉getClass()方法,即可得到字段数量方法5:使用Java 8的Stream API•使用Java 8的Stream API和Lambda表达式•使用Class类的getDeclaredFields()方法获取字段数组•使用Stream类的filter()方法过滤掉名为”class”的字段•使用Stream类的count()方法获取字段数量方法6:使用Lombok的@EqualsAndHashCode注解•引入Lombok库•在Entity类上使用@EqualsAndHashCode注解•使用编译器自动生成的equals()和hashCode()方法获取字段数量方法7:手动统计字段数量•手动编写一个方法,通过判断每个字段是否为空来统计字段数量以上是几种常用的方法,可以根据具体需求选择合适的方法来得到Entity对象的字段数量。

扩展JPA方法,重写save方法

扩展JPA方法,重写save方法

扩展JPA⽅法,重写save⽅法为什么要重构save?jpa提供的save⽅法会将原有数据置为null,⽽⼤多数情况下我们只希望跟新⾃⼰传⼊的参数,所以便有了重写或者新增⼀个save⽅法。

本着解决这个问题,⽹上搜了很多解决⽅案,但是没有找到合适的,于是⾃⼰研究源码,先展⽰⼏个重要源码1、SimpleJpaRepository⽅法实现类,由于代码过多只展⽰部分源码public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpecificationExecutor<T> {private static final String ID_MUST_NOT_BE_NULL = "The given id must not be null!";private final JpaEntityInformation<T, ?> entityInformation;private final EntityManager em;private final PersistenceProvider provider;@Nullableprivate CrudMethodMetadata metadata;public SimpleJpaRepository(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {Assert.notNull(entityInformation, "JpaEntityInformation must not be null!");Assert.notNull(entityManager, "EntityManager must not be null!");this.entityInformation = entityInformation;this.em = entityManager;this.provider = PersistenceProvider.fromEntityManager(entityManager);}public SimpleJpaRepository(Class<T> domainClass, EntityManager em) {this(JpaEntityInformationSupport.getEntityInformation(domainClass, em), em);}public void setRepositoryMethodMetadata(CrudMethodMetadata crudMethodMetadata) {this.metadata = crudMethodMetadata;}@Nullableprotected CrudMethodMetadata getRepositoryMethodMetadata() {return this.metadata;}protected Class<T> getDomainClass() {return this.entityInformation.getJavaType();}private String getDeleteAllQueryString() {return QueryUtils.getQueryString("delete from %s x", this.entityInformation.getEntityName());}@Transactionalpublic <S extends T> S save(S entity) {if (this.entityInformation.isNew(entity)) {this.em.persist(entity);return entity;} else {return this.em.merge(entity);}}}2、JpaRepositoryFactoryBeanpublic class JpaRepositoryFactoryBean<T extends Repository<S, ID>, S, ID> extends TransactionalRepositoryFactoryBeanSupport<T, S, ID> {@Nullableprivate EntityManager entityManager;public JpaRepositoryFactoryBean(Class<? extends T> repositoryInterface) {super(repositoryInterface);}@PersistenceContextpublic void setEntityManager(EntityManager entityManager) {this.entityManager = entityManager;}public void setMappingContext(MappingContext<?, ?> mappingContext) {super.setMappingContext(mappingContext);}protected RepositoryFactorySupport doCreateRepositoryFactory() {Assert.state(this.entityManager != null, "EntityManager must not be null!");return this.createRepositoryFactory(this.entityManager);}protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {return new JpaRepositoryFactory(entityManager);}public void afterPropertiesSet() {Assert.state(this.entityManager != null, "EntityManager must not be null!");super.afterPropertiesSet();}} 根据源码及⽹上资料总结如下⽅案⼀、重写save优势:侵⼊性⼩,缺点将原⽅法覆盖。

JPAsave()方法将字段更新为null的解决方案

JPAsave()方法将字段更新为null的解决方案

JPAsave()⽅法将字段更新为null的解决⽅案这篇⽂章主要介绍了JPA save()⽅法将字段更新为null的解决⽅案,⽂中通过⽰例代码介绍的⾮常详细,对⼤家的学习或者⼯作具有⼀定的参考学习价值,需要的朋友可以参考下今天在开发上碰到⼀个问题,在做页⾯展⽰的时候传给前端⼗个字段,前端修改了其中3个的值,所以只传了3个值给后端,其余字段默认为null,更新后其他7个字段在全部变为了空值。

在前端没法全量回传所有属性的前提下,由后端来处理这类问题。

解决⽅法:1.写⼀个⼯具⽅法(UpdateUtil)⽤来筛选出所有的空值字段2.更新时先通过id搜索原始对象,通过findone()等都可以3.将前端传来的不为空参数(也即是要修改值)copy覆盖原始对象属性值,通过BeanUtils.copyNullProperties(Object source, Object target)以下是⼯具⽅法:/*** 更新⽤⼯具类(忽略为null的字段)*/public class UpdateUtil {/*** 所有为空值的属性都不copy** @param source* @param target*/public static void copyNullProperties(Object source, Object target) {BeanUtils.copyProperties(source, target, getNullField(source));}/*** 获取属性中为空的字段** @param target* @return*/private static String[] getNullField(Object target) {BeanWrapper beanWrapper = new BeanWrapperImpl(target);PropertyDescriptor[] propertyDescriptors = beanWrapper.getPropertyDescriptors();Set<String> notNullFieldSet = new HashSet<>();if (propertyDescriptors.length > 0) {for (PropertyDescriptor p : propertyDescriptors) {String name = p.getName();Object value = beanWrapper.getPropertyValue(name);if (Objects.isNull(value)) {notNullFieldSet.add(name);}}}String[] notNullField = new String[notNullFieldSet.size()];return notNullFieldSet.toArray(notNullField);}}以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

wrapper用法

wrapper用法

wrapper用法Wrapper一种用于包装函数、方法、类和服务的设计模式,它最主要的功能是修改和调整包装对象的行为,通过改变包装对象的内部实现和附加额外功能,从而实现针对这些包装对象的灵活、高效的调整。

为了更好地理解和实现Wrapper,我们首先要了解它的两个基本概念:包装对象和Wrapper。

一、包装对象包装对象就是要被Wrapper装的对象,它可以是函数、方法、类和服务等。

包装对象的行为可以通过在Wrapper中实现额外的功能来改变和调整。

二、WrapperWrapper就是用于实现Wrapper能的类,它的功能可以用于修改和调整包装对象的行为,从而达到灵活、高效的改变和调整。

Wrapper中的包装模式可以分为两种:装饰器模式和代理模式。

装饰器模式使用Wrapper来修饰和装饰包装对象,可以实现对包装对象的修改和调整;代理模式则是通过Wrapper来代理包装对象,从而实现对包装对象的行为控制和修改。

三、使用Wrapper优势1.一接口:使用Wrapper可以把多个不同的对象和服务统一成一个统一的接口,从而实现更加灵活的操作和控制;2.调性强:Wrapper可以很好地支持扩展和动态调整,因为它们可以通过增加新的Wrapper来改变和调整包装对象的行为,从而实现更加灵活的操作和控制;3.块化:使用Wrapper可以实现更加灵活的模块化,在不改变原有对象和服务的基础上,通过增加新的Wrapper来实现复杂的模块化操作,从而实现更加灵活的操作和控制;4.率高:Wrapper的使用可以提高程序的效率,因为它可以利用现有的对象和服务,从而把复杂的操作集中到Wrapper中,而不必重新实现复杂的操作,从而极大地提高效率;5.领域:Wrapper可以跨越不同领域之间的操作,因为它可以利用现有的类和服务,从而实现复杂的操作,从而实现跨领域的操作和控制。

总之,Wrapper法非常有用,它可以把多个不同的类和服务统一成一个统一的接口,可以有效地改变和调整包装对象的行为,从而实现更加灵活的操作和控制,而且可以跨越不同领域之间的操作,从而实现跨领域的操作和控制,为程序的实现提供了可能性和便利性。

spring框架在什么地方真正实例化了Bean

spring框架在什么地方真正实例化了Bean

这是一个问题,问很多人都不清楚的问题,也许有一部分人知道spring是隐式得调用DefaultLisTableBeanFactory的父类AbstractBeanFactory的getBean()方法来真正实例化对象的,那么,这个getBean()到底是在什么地方调用的呢?那么,我们就来分析一下吧。

1:基于springMVC框架的项目:这个就很简单了,我们都知道基于spring的web项目。

IOC容器初始化的入口全部在web.xml里面:<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>通过这个ContextLoaderListener,spring完成了BeanDefinition的解析,注册。

也就是完成了对XML配置文件的解读,并把所有定义的bean信息作为spring特有的数据结构存储到了BeanDefinition集合。

并将这个集合作为hasMap保存在容器里。

并且在这个过程中,建立了web项目的上下文环境。

接下来,我们看springMvc的容器初始化,他是通过web.xml的这个入口进入的。

通过这个DispatcherServlet的入口,spring会再次建立一个上下文在DispatcherServlet建立起来的上下文之上的。

<servlet><servlet-name>tms</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>tms</servlet-name><url-pattern>*.htm</url-pattern></servlet-mapping>好了,接下来的事情就很明显了,项目启动起来后,当一个URL请求过来的时候,就会进入 DispatcherServlet,在这个类里面,spring调用了getBean()方法,对URL请求需要用到的对象,都进行了实例化。

关于QueryWrapper的用法

关于QueryWrapper的用法

关于QueryWrapper的⽤法关于QueryWrapper的⽤法1.项⽬中的遇到过的问题if(!ParamsVerifyUtils.isEmpty(param.get("createName"))) {wrapper.like("create_name", param.get("createName").toString()).or().like("info",param.get("createName").toString());}wrapper.ne("status", "-99");wrapper.orderByDesc("create_time");return wrapper;这个是错误的这⾥的 .ne就没有⽣效正确的写法wrapper.ne("status", "-99");if(!ParamsVerifyUtils.isEmpty(param.get("createName"))) {wrapper.like("create_name", param.get("createName").toString()).or().like("info",param.get("createName").toString());}wrapper.orderByDesc("create_time");return wrapper;附带⼀张wrapper完整的⽅法顺序图查询⽅式说明setSqlSelect 设置 SELECT 查询字段where WHERE 语句,拼接 + WHERE 条件and AND 语句,拼接 + AND 字段=值andNew AND 语句,拼接 + AND (字段=值)or OR 语句,拼接 + OR 字段=值orNew OR 语句,拼接 + OR (字段=值)eq 等于=allEq 基于 map 内容等于=ne 不等于<>gt ⼤于>ge ⼤于等于>=lt ⼩于<le ⼩于等于<=like 模糊查询 LIKEnotLike 模糊查询 NOT LIKEin IN 查询notIn NOT IN 查询isNull NULL 值查询isNotNull IS NOT NULLgroupBy 分组 GROUP BYhaving HAVING 关键词orderBy 排序 ORDER BYorderAsc ASC 排序 ORDER BYorderDesc DESC 排序 ORDER BYexists EXISTS 条件语句notExists NOT EXISTS 条件语句between BETWEEN 条件语句notBetween NOT BETWEEN 条件语句addFilter ⾃由拼接 SQLlast 拼接在最后,例如:last(“LIMIT 1”)。

【Spring】InitializingBean与DisposableBean接口的实现原理(六)

【Spring】InitializingBean与DisposableBean接口的实现原理(六)

【Spring】InitializingBean与DisposableBean接⼝的实现原理(六) 关于在Spring 容器初始化和销毁 bean 前所做的操作有三种⽅式定义:第⼀种:通过@PostConstruct 和 @PreDestroy ⽅法实现初始化后和销毁bean之前进⾏的操作第⼆种:通过bean实现InitializingBean和 DisposableBean接⼝第三种:通过在xml中配置init-method 和 destory-method⽅法,或者配置@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod") 注解 执⾏顺序:@PostConstruct -> InitializingBean -> 配置initMethod -> @PreDestroy -> DisposableBean -> 配置destroyMethod 本章介绍第⼆种 第⼀种见:⼀、InitializingBean 和 @DisposableBean 接⼝使⽤1public class BeanPerson implements InitializingBean, DisposableBean {23public void say(String word) {4 System.out.println("Hello, " + word);5 }67public BeanPerson() {8 System.out.println("BeanPerson() ");9 }1011 @Override12public void afterPropertiesSet() throws Exception {13 System.out.println("afterPropertiesSet()......");14 }1516 @Override17public void destroy() throws Exception {18 System.out.println("destroy()......");19 }2021 }⼆、原理图 实现原理是通过代码逻辑判断bean的类型,是否实现的对应的接⼝三、InitializingBean 接⼝实现原理1、实例化bean时,createBeat()->doCreateBeat()->initializeBean() 初始化 initializeBean() ⽅法如下:1protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { 2if (System.getSecurityManager() != null) {3 AccessController.doPrivileged((PrivilegedAction<Object>) () -> {4 invokeAwareMethods(beanName, bean);5return null;6 }, getAccessControlContext());7 } else {8// 若bean实现了XXXAware接⼝进⾏⽅法的回调9 invokeAwareMethods(beanName, bean);10 }1112 Object wrappedBean = bean;13if (mbd == null || !mbd.isSynthetic()) {14// ⽀持初始化前bean的后置处理器15 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);16 }1718try {19// 调⽤初始化⽅法20 invokeInitMethods(beanName, wrappedBean, mbd);21 } catch (Throwable ex) {22throw new BeanCreationException(23 (mbd != null ? mbd.getResourceDescription() : null),24 beanName, "Invocation of init method failed", ex);25 }26if (mbd == null || !mbd.isSynthetic()) {27 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);28 }2930return wrappedBean;31 }2、调⽤了初始化⽅法 invokeInitMethods() ,如下:1protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)2throws Throwable {3// 判断容器中是否实现了InitializingBean接⼝4boolean isInitializingBean = (bean instanceof InitializingBean);5if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {6if (logger.isTraceEnabled()) {7 logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");8 }9if (System.getSecurityManager() != null) {10try {11 AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {12 ((InitializingBean) bean).afterPropertiesSet();13return null;14 }, getAccessControlContext());15 } catch (PrivilegedActionException pae) {16throw pae.getException();17 }18 } else {19// 回调实现InitializingBean接⼝的afterPropertiesSet()⽅法20 ((InitializingBean) bean).afterPropertiesSet();21 }22 }2324if (mbd != null && bean.getClass() != NullBean.class) {25// bean定义中看是否有配置的init⽅法26 String initMethodName = mbd.getInitMethodName();27// 判断⾃定义的init⽅法名称不叫afterPropertiesSet28if (StringUtils.hasLength(initMethodName) &&29 !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&30 !mbd.isExternallyManagedInitMethod(initMethodName)) {31// 调⽤配置的初始化⽅法32 invokeCustomInitMethod(beanName, bean, mbd);33 }34 }35 } 其中,判断类bean是否属于InitializingBean接⼝,然后调⽤了afterPropertiesSet()⽅法四、DisposableBean 接⼝实现原理1、在容器关闭时,调⽤⽅法链:context.clonse() -> doClose() -> destroyBeans() -> destroySingletons() ->destroySingleton() 销毁单例⽅法 destroySingleton() 如下:1public void destroySingleton(String beanName) {2// Remove a registered singleton of the given name, if any.3// 移除缓存4 removeSingleton(beanName);56// Destroy the corresponding DisposableBean instance.7 DisposableBean disposableBean;8// 加锁9synchronized (this.disposableBeans) {10// 根据名称,从需要销毁的是实例集合移除实例,得到disposableBean11 disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);12 }13// 销毁bean14 destroyBean(beanName, disposableBean);15 }2、从bean⼯⼚的 disposableBeans 中,获取移除对象,⽽这个 disposableBeans 销毁对象集合中的对象是从注册的时候来的 查看bean创建逻辑: createBeat()->doCreateBeat(),在 doCreateBeat() 调⽤了registerDisposableBeanIfNecessary() ⽅法 1protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)2throws BeanCreationException {34// Instantiate the bean.5// 实例化的bean会封装成⼀个BeanWrapper对象6// BeanWrapper是对Bean的包装,其接⼝中所定义的功能很简单包括设置获取被包装的对象,获取被包装bean的属性描述器,7// 由于BeanWrapper接⼝是PropertyAccessor的⼦接⼝,因此其也可以设置以及访问被包装对象的属性值。

@Mapper注解和@MapperScan注解的关联性,以及源码分析

@Mapper注解和@MapperScan注解的关联性,以及源码分析

@Mapper注解和@MapperScan注解的关联性,以及源码分析@Mapper注解和@MapperScan注解是我们使⽤mybatis-spring的常⽤注解,之前为了探究两个注解的关联性,百度了⼀波⽂章,但是都将@Mapper注解和@MapperScan注解分开讲解。

索性⾃⼰结合mybatis-spring和spring-boot源码分析,探究两个注解的关联性。

整篇⽂章以MapperScannerRegistrar、MybatisAutoConfiguration、AutoConfiguredMapperScannerRegistrar三个类作为核⼼类分析。

结论已在⽂章最下⽅贴出。

⼀、启动类定义MapperScan注解的⽅式1,⼊⼝得从@MapperScan注解来说从@MapperScan注解的内容可以看出,如果SpringBoot主类定义了MapperScan注解,那么MapperScannerRegistrar类会将BeanDefinition注⼊到SpringBoot的BeanDefinitionRegistry组件中,这⾥BeanDefinitionRegistry我就不多加赘述,有兴趣的朋友可以看看SpringBoot加载BeanDefinitionRegistry与BeanDefinitionRegistry实例化Bean的源码。

2,观察MapperScannerRegistrar类,其实现了ImportBeanDefinitionRegistrar接⼝,那么在SpringBoot的refresh上下⽂的invokeBeanDefinitionRegistryPostProcessors⽅法的过程中会调⽤MapperScannerRegistrar的registerBeanDefinitions⽅法,⽽MapperScannerRegistrar的registerBeanDefinitions⽅法中最主要的⽅法是registerBeanDefinitions⽅法。

querywrapper用法

querywrapper用法

querywrapper用法本文介绍了querywrapper的概念和用法。

Querywrapper是一种实用的SQL查询构建器,可以用来构建安全的可复用的查询,并且具有高度可定制的功能。

本文将介绍QueryWrapper的背景、安装和使用,以及它与其他库的比较。

一、QueryWrapper背景QueryWrapper是一种功能强大的SQL查询构建器,可以帮助开发人员快速构建安全而可复用的SQL查询。

QueryWrapper的目的是提供开发人员一种更有效地构建可复用的SQL查询的方法。

QueryWrapper的优势在于它的可扩展性和易用性。

它支持灵活的查询构建,可以支持表和视图中的任何字段,并且可以支持复杂的查询(例如条件筛选、聚合函数和子查询等)。

此外,它还支持可定制参数,通过哪些参数可以很容易地组合起来构建更复杂的查询。

二、QueryWrapper安装要安装QueryWrapper,需要安装Node.js和npm(Node Package Manager),Node.js可以运行在Windows、Mac OS X和Linux等平台上,可以从Node.js官网下载。

安装完Node.js之后,可以使用npm来安装QueryWrapper,使用的命令是:npm install querywrapper安装完成后可以在node_modules文件夹中查看QueryWrapper,可以使用require指令来加载QueryWrapper,也可以使用依赖注入来加载QueryWrapper。

三、QueryWrapper使用QueryWrapper可以用于构建各种类型的SQL查询,例如查询、更新、插入和删除等。

它有一套可定制的参数,可以用来定义字段、表、条件和排序等。

首先,可以使用QueryWrapper创建一个新的查询对象:var query = new QueryWrapper();然后就可以使用QueryWrapper的参数构造查询,例如可以使用select()函数来指定要查询的字段:query.select([id name])也可以使用from()函数来指定要查询的表:query.from(users查询可以使用where()函数来进行条件筛选:query.where(name = john也可以使用orderBy()函数来进行排序:query.orderBy(name asc最后,可以使用toString()函数构造出最终的SQL查询:query.toString() // SELECT id, name FROM users WHERE name = john ORDER BY name ASC四、QueryWrapper与其他库的比较QueryWrapper在查询构建方面非常强大,但也有一些其他的库可以用于构建查询,例如Knex.js和Sequelize.js等。

java反射获取实体类的get方法

java反射获取实体类的get方法

java反射获取实体类的get方法反射是Java中一种强大的机制,它允许我们在运行时动态地获取对象、类的信息,并且可以调用对象的方法、访问对象的属性。

在Java中,我们可以使用反射来获取类的get方法。

获取实体类的get方法的过程分为以下几个步骤:1. 获取类的Class对象:在Java中,想要获取类的信息,首先需要获取类的Class对象。

我们可以通过Class类的静态方法forName()来获取一个类的Class对象,例如:Class<?> clazz = Class.forName("er");2. 获取类的所有方法:通过Class对象的getMethods()方法可以获取类的所有方法,包括继承的方法和自己声明的方法。

该方法返回一个Method数组。

```javaMethod[] methods = clazz.getMethods();```3. 筛选出get方法:遍历方法数组,通过方法名的前缀判断是否为get方法。

在JavaBean规范中,get方法的命名一般为"get"或"is"开头,后面跟着属性名的首字母大写。

```javaList<Method> getMethods = new ArrayList<>();for (Method method : methods) {String methodName = method.getName();if (methodName.startsWith("get") ||methodName.startsWith("is")) {getMethods.add(method);}}```4. 获取属性名:通过get方法的方法名获取对应的属性名。

如果方法名以"get"开头,则属性名为方法名去掉"get"并将首字母改为小写;如果方法名以"is"开头,则属性名为方法名去掉"is"并将首字母改为小写。

beanutil.beantomap 的用法

beanutil.beantomap 的用法

beanutil.beantomap的用法beanutil.beantlrmap是Java中一个常用的工具类,用于将对象映射到映射表中。

它提供了一组方法,可以帮助开发人员更加方便地操作对象和映射表之间的转换。

1.将对象转换为映射表中的记录:通过将对象属性与映射表中的列名进行匹配,可以将对象转换为映射表中的记录,并将其保存到数据库中。

2.将映射表中的记录转换为对象:通过匹配映射表中的记录与对象的属性,可以将映射表中的记录转换为相应的对象,从而方便地进行后续的处理和操作。

3.支持自定义映射规则:开发者可以通过实现自定义的映射规则类,来实现更加灵活的映射转换逻辑。

下面是一个简单的示例,展示了如何使用beanutil.beantlrmap将对象转换为映射表中的记录:1.创建一个对象,并设置其属性值:```javaPersonperson=newPerson();person.setName("John");person.setAge(30);```2.创建一个beanutil.beantlrmap实例,并指定映射表的表名和列名:```javaBeanMapper<Person>mapper=newBeanMapper<Person>().ofTableName("perso n_table").mapColumns("id","name","age");```3.使用mapper将对象转换为映射表中的记录:```javaObject[]record=mapper.toRecord(person);```现在,record数组中包含了person对象的属性值,可以将其保存到数据库中。

如果要将映射表中的记录转换为对象,可以按照以下步骤进行:1.创建一个beanutil.beantlrmap实例,并指定要匹配的记录和对象的属性:```javaBeanMapper<Person>mapper=newBeanMapper<Person>().ofTableName("perso n_table").mapColumns("id","name","age").toObject(Person.class);```2.使用mapper将映射表中的记录转换为对象:```javaPersonperson=mapper.fromRecord(record);```这样,person对象就得到了映射表中的记录的属性值。

ClassPathXmlApplicationContext的启动

ClassPathXmlApplicationContext的启动

ClassPathXmlApplicationContext的启动Spring将ApplicationContext启动的全过程,refresh函数中包含了⼏乎ApplicationContext中提供的全部功能,⽽且此函数中逻辑⾮常清晰明了,很容易分析对应的层次及逻辑。

:ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {//准备刷新的上下⽂环境,例如对系统属性或者环境变量进⾏准备及验证。

prepareRefresh();//初始化BeanFactory,并进⾏XML⽂件读取,//这⼀步之后,ClassPathXmlApplicationContext实际上就已经包含了BeanFactory所提供的功能,也就是可以进⾏Bean的提取等基础操作了。

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//对BeanFactory进⾏各种功能填充,@Qualifier与@Autowired这两个注解正是在这⼀步骤中增加的⽀持。

//设置@Autowired和 @Qualifier注解解析器QualifierAnnotationAutowireCandidateResolver prepareBeanFactory(beanFactory);try {//⼦类覆盖⽅法做额外的处理,提供了⼀个空的函数实现postProcessBeanFactory来⽅便程序员在业务上做进⼀步扩展。

allow-circular-references 实现原理

allow-circular-references 实现原理

allow-circular-references 允许循环依赖,它的实现原理主要是通过两个方面来实现:
1. 循环检测:Spring在实例化bean时,会检测是否存在循环依赖的情况。

如果检测到循环依赖,Spring会记录下这个循环依赖,并尝试使用“构造器代理”或者“setter代理”来打破这个循环。

2. 构造器代理与setter代理:Spring在打破循环依赖时,会使用代理模式。

构造器代理是指Spring在实例化bean时,会先创建一个BeanWrapper对象,然后将这个BeanWrapper对象传递给bean的构造器。

在构造器中,Spring会使用BeanWrapper对象来注入bean的属性。

setter代理是指Spring在调用bean的setter方法时,会使用BeanWrapper对象来注入bean的属性。

总的来说,allow-circular-references的实现原理是通过循环检测和代理模式来打破循环依赖。

IOC概述和基本实现流程分析

IOC概述和基本实现流程分析

IOC概述和基本实现流程分析那天有人问我:“IOC到底啥用,感觉用处不大,还特麻烦!”那天有人问我:“IOC到底啥用,感觉用处不大,还多一些麻烦!”关于IOC的话题,已经很多很多了,但是很多都处于了解,或者仅仅使用于框架上,这里我分享一些自己的理解,然后实现一个类似spring ioc 的东西。

一、什么是IOC维基百科上说到:2004年Martin Fowler 提出了“控制反转的”概念,他得出的结论是:依赖对象的获得被反转了。

后来为这个创造了一个更好的名字:依赖注入(IOC = Inversion of Control).简单的解释是:系统的运作是通过两个或多个类的合作来实现业务逻辑,这使得每个对象都需要与其合作的对象的引用(依赖关系),这个依赖对象以前是通过自身实现去获得,现在通过一个容器统一的管理这些依赖关系,从而获得这种依赖的这种实现方式,我们可以成为IOC。

二、为什么要用IOC我们知道任何事物的诞生,总会有其目的,这里我们先模拟几种场景,让我们更清楚的了解IOC是如何诞生的。

例1: A类需要用到业务B类的引用,这时候我们在A 里面进行B b = new B();随着系统的庞大,我可能后面C,F,G...N 都要用B类的引用,我们在每个类里面都进行类似A的操作吗?好吧,你这样做了!但是突然有一天需要变化,B类我们必须要一个带参构造public B(Stirng str){}.那么你要把所有的类的引用全部修改一次吗?如果可能继续扩展,继续变化呢?例2:同样很多类都需要B类的引用,B是A接口的实现,我现在不想用实现类B了,从新实现一个类C,全部替换过来,那么你需要从N 个类里面进行修改吗?例3:大部分情况下类的关系是:A需要B,B需要C,C需要D,D需要...!然后经常的变动是:B不满足了,需要改变,或者替换,然后可能D也需要替换等,然后我们就各个地方到处更改吗?说道这里,我们先看看按原始方式做的优劣:●优点:1.速度快,写得舒服!●缺点:1.创建太多对象,占用内存空间。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

EJB的框架采用了一种侵略性(Invasive)的方法来设计对象,它要求你在设计中加入符合EJB规范的代码。

一些轻量级的COP框架,例如Avalon,也要求对象设计时必须符合某种规范,例如Serviceable接口,这种做法是典型的Type 1做法。

这种设计思路要求Spring采用一种动态的、灵活的方式来设计框架。

所以spring大量采用了反射。

首先spring要解决的一个问题就是如何管理bean。

因为IOC的思想要求bean之间不能够直接调用,而应该采用一种被动的方式进行协作。

所以bean的管理是spring中的核心部分。

反射和内省在代码的层次上思考问题,有时候能够带来出人意料的灵活性。

但它的使用有时候也是一个哲学问题,不论是在ORM设计还是在AOP设计上都出现了类似的问题-究竟是使用反射,还是使用代码生成。

在Spring中,处理这个问题的核心是在org.springframework.beans包中。

而其中最为核心的部分,则是BeanWrapper。

BeanWrapper,顾名思义,就是bean的包装器。

所以,它的主要工作,就是对任何一个bean,进行属性(包括内嵌属性)的设置和方法的调用。

在BeanWrapper的默认实现类BeanWrapperImpl 中,虽然代码较长,但完成的工作却是非常的集中的。

BeanWrapper的深入研究我们看看这个BeanWrapper是如何发挥运作的,假设我们有两个bean:public class Company {private String name;private Employee managingDirector;public String getName() {return ;}public void setName(String name) { = name;}public Employee getManagingDirector() {return this.managingDirector;}public void setManagingDirector(Employee managingDirector) {this.managingDirector = managingDirector;}}public class Employee {private float salary;public float getSalary() {return salary;}public void setSalary(float salary) {this.salary = salary;}}然后我们使用BeanWrapper来调用这两个bean:Company c = new Company();BeanWrapper bwComp = BeanWrapperImpl(c);// setting the company name...bwComp.setPropertyValue("name", "Some Company Inc.");// ... can also be done like this:PropertyValue v = new PropertyValue("name", "Some Company Inc.");bwComp.setPropertyValue(v);// ok, let's create the director and tie it to the company:Employee jim = new Employee();BeanWrapper bwJim = BeanWrapperImpl(jim);bwJim.setPropertyValue("name", "Jim Stravinsky");bwComp.setPropertyValue("managingDirector", jim);// retrieving the salary of the managingDirector through the companyFloat salary = (Float)bwComp.getPropertyValue("managingDirector.salary");看起来麻烦了许多,但是这样spring就可以使用统一的方式来管理bean的属性了。

Bean的制造工厂有了对单个Bean的包装,还需要对多个的bean进行管理。

在spring中,把bean纳入到一个核心库中进行管理。

bean的生产有两种方法:一种是一个bean产生多个实例,一种是一个bean只产生一个实例。

如果对设计模式熟悉的话,我们就会想到,前者可以采用Prototype,后者可以采用Singleton。

注意到,反射技术的使用使得我们不再像原始的工厂方法模式那样创建对象。

反射可以非常灵活的根据类的名称创建一个对象。

所以spring只使用了Prototype和Singleton这两个基本的模式。

spring正是这样处理的,但是我们希望用户能够维护统一的接口,而不需要关心当前的bean到底是Prototype产生的独立的bean,还是Singleton产生的共享的bean。

所以,在org.springframework.beans.factory 包中的BeanFactory定义了统一的getBean方法。

JDBC再封装JDBC优雅的封装了底层的数据库,但是JDBC仍然存在诸多的不变。

你需要编写大量的代码来完成CRUD操作,而且,JDBC无论是遇到什么样的问题,都抛出一个SQLException,这种做法在异常使用上被称为不完备的信息。

因为问题可能是很复杂的,也许是数据库连接的问题,也许是并发控制的问题,也许只是SQL语句出错。

没有理由用一个简单的SQLException就搞定全部的问题了,这种做法有些不负责任。

针对这两个问题,Spring Framework提出了两种解决方法:首先,提供一个框架,把JDBC 应用中的获取连接、异常处理、释放等比较通用的操作全部都集中起来,用户只需要提供特定的实现就OK 了。

实现的具体细节采用的是模板方法。

举个例子,在org.springframework.jdbc.object包中,MappingSqlQuery 类实现了将SQL查询映射为具体的业务对象。

JavaDoc中这样写到:Reusable query in which concrete subclasses must implement the abstract mapRow(ResultSet, int) method to convert each row of the JDBC ResultSet into an object. 用户必须实现mapRow方法,这是典型模板方法的应用。

我们拿一个具体的例子来看看:class UserQuery extends MappingSqlQuery {public UserQuery(DataSource datasource) {super(datasource, "SELECT * FROM PUB_USER_ADDRESS WHERE USER_ID = ?");declareParameter(new SqlParameter(Types.NUMERIC));compile();}// Map a result set row to a Java objectprotected Object mapRow(ResultSet rs, int rownum) throws SQLException {User user = new User();user.setId(rs.getLong("USER_ID"));user.setForename(rs.getString("FORENAME"));return user;}public User findUser(long id) {// Use superclass convenience method to provide strong typingreturn (User) findObject(id);}}其次是第二个问题,最麻烦的地方应该说是需要截住JDBC的异常,然后判断异常的类型,并重新抛出异常。

错误的问题可以通过连接来获取,所以麻烦的是如何截获异常。

Spring Framework采用的方法是回调,处理回调的类在Spring Framework中被称为templateJdbcTemplate template = new JdbcTemplate(dataSource);final List names = new LinkedList();template.query("SELECT FROM USER",new RowCallbackHandler() {public void processRow(ResultSet rs) throws SQLException {names.add(rs.getString(1));}});回调函数是一个匿名类,其中也使用了模板方法,异常的处理都在父类中完成了。

层间松耦合在开放源码界已经出现了大量的基于MVC的Web容器,但是这些容器都仅限于Web的范围,不涉及Web层次后端的连接,spring作为一个整体性的框架,定义了一种Web层和后端业务层的连接方式,这个思路仍然疏运图MVC的范畴,但耦合更松散,不依赖于具体的集成层次。

public class GoogleSearchControllerimplements Controller {private IGoogleSearchPort google;private String googleKey;public void setGoogle(IGoogleSearchPort google) {this.google = google;}public void setGoogleKey(String googleKey) {this.googleKey = googleKey;}public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {String query = request.getParameter("query");GoogleSearchResult result =// Google property definitions omitted...// Use google business objectgoogle.doGoogleSearch(this.googleKey, query,start, maxResults, filter, restrict, safeSearch, lr, ie, oe);return new ModelAndView("googleResults", "result", result);}}回调函数是一个匿名类,其中也使用了模板方法,异常的处理都在父类中完成了。

相关文档
最新文档