关于spring:springboot自动配置的秘密

前言       随着互联网越来越风行,springboot曾经成为咱们无论是工作,还是面试当中,不得不把握的技术。说起springboot笔者认为最重要的性能非主动配置莫属了,为什么这么说?如果参加过以前spring简单我的项目的敌人必定,有过这样的经验,每次须要一个新性能,比方事务、AOP等,须要大量的配置,须要导出找jar包,时不时会呈现jar兼容性问题,能够说苦不堪言。       springboot的呈现得益于“习惯优于配置”的理念,没有繁琐的配置、难以集成的内容(大多数风行第三方技术都被集成),这是基于Spring 4.x以上的版本提供的按条件配置Bean的能力。有了springboot的主动配置的性能,咱们能够疾速的开始一个我的项目。 一 什么是主动配置不晓得敌人们在工作当中有没有这样的经验: 1.1 引入redisTemplate只有咱们在pom.xml文件中引入spring-boot-starter-data-redis-xxx.jar包,而后只有在配置文件中配置redis连贯,如: spring.redis.database = 0spring.redis.timeout = 10000spring.redis.host = 10.72.16.9spring.redis.port = 6379spring.redis.pattern = 1就能够在service办法中间接注入StringRedisTemplate对象的实例,能够间接应用了。敌人们有没有想过这是为什么? @Autowiredprivate StringRedisTemplate stringRedisTemplate;1.2  引入transactionTemplate在我的项目中只有引入spring-boot-starter-xxx.jar,事务就主动失效了,并且能够间接在service办法中间接注入TransactionTemplate,用它开发编程式事务代码。是不是很神奇?这又是为什么? 1.3  应用@ConfigurationProperties应用@ConfigurationProperties能够把指定门路下的属性,间接注入到实体对象中,看看上面这个例子: @Data@Component@ConfigurationProperties("jump.threadpool")public class ThreadPoolProperties { private int corePoolSize; private int maxPoolSize; private int keepAliveSeconds; private int queueCapacity;}只有application.properties这样配置,就能够主动注入到下面的实体中 jump.threadpool.corePoolSize=8jump.threadpool.maxPoolSize=16jump.threadpool.keepAliveSeconds=10jump.threadpool.queueCapacity=100没错,这三个例子都是springboot主动配置在起作用,咱们分为两种状况:bean的主动配置 和 属性的主动配置。 二 工作原理 2.1 bean的主动配置Spring Boot的启动类上有一个@SpringBootApplication注解,这个注解是Spring Boot我的项目必不可少的注解。 咱们先看看@SpringBootApplication注解 它下面定义了另外一个注解:@EnableAutoConfiguration 该注解的要害性能由@Import提供,其导入的AutoConfigurationImportSelector的selectImports()办法通过SpringFactoriesLoader.loadFactoryNames()扫描所有具备META-INF/spring.factories的jar包上面key是EnableAutoConfiguration全名的,所有主动配置类。 咱们看看springboot的spring-boot-autoconfigure-xxx.jar 该jar包外面就有META-INF/spring.factories文件。 这个spring.factories文件是一组一组的key=value的模式,其中一个key是EnableAutoConfiguration类的全类名,而它的value是一个xxxxAutoConfiguration的类名的列表,这些类名以逗号分隔。 @EnableAutoConfiguration注解通过@SpringBootApplication被间接的标记在了Spring Boot的启动类上。在SpringApplication.run(...)的外部就会执行selectImports()办法,找到所有JavaConfig主动配置类的全限定名对应的class,而后将所有主动配置类加载到Spring容器中。 SpringApplication.run(...)办法怎么调到selectImports()办法的 加载过程大略是这样的: SpringApplication.run(...)办法  》  AbstractApplicationContext.refresh()办法  》  invokeBeanFactoryPostProcessors(...)办法  》  PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(...) 办法  》 ...

October 8, 2020 · 1 min · jiezi

关于spring:手写SpringBoot近况IoC模块已经完成

jsoncat: https://github.com/Snailclimb/jsoncat (About仿 Spring Boot 但不同于 Spring Boot 的一个轻量级的 HTTP 框架)边看英雄联盟较量,边和小伙伴们简略聊聊简易版的“Spring Boot”的近况吧!JDG 冲冲冲!!! 全文内容不会很多,因为不会具体介绍实现过程,大家节假日必定也不想看。前面会具体写文章分享本人的实现过程比方 Spring MVC、IoC 模块到底是咋实现的(最简化准则实现,能用起码的代码就用起码的代码。便于保护,便于学习)。 9.29号的早晨,我曾经在老家了。 早晨和女票还有妹妹一起开黑打完游戏之后,曾经到了快11点。有点睡不着,心田躁动,就把 HTTP 框架的 IoC 的基本功能给实现了。 第二天,我又抽出了一些工夫,对其进行了优化和重构。 目前不光反对 @Autowired(注入对象) 和 @Component (申明对象被 IoC 容器治理),还反对 @Qualifier(指定注入的bean)。 简略给大家看一下成果! 申明一个接口:SmsService.java public interface SmsService { String send(SmsDto smsDto);}实现类1:AliSmsServiceImpl.java @Component(name = "aliSmsServiceImpl")public class AliSmsServiceImpl implements SmsService { @Override public String send(SmsDto smsDto) { System.out.println("send message to " + smsDto.getPhone()); return AliSmsServiceImpl.class.getSimpleName(); }}实现类2:QiNiuSmsServiceImpl.java @Component(name = "qiNiuSmsServiceImpl")public class QiNiuSmsServiceImpl implements SmsService { @Override public String send(SmsDto smsDto) { System.out.println("send message to " + smsDto.getPhone()); return QiNiuSmsServiceImpl.class.getSimpleName(); }}post申请传输类:SmsDto.java ...

October 5, 2020 · 1 min · jiezi

关于spring:第六阶段-第二模块

在程序启动期spring 就会去创立一些对象存储到ioc autowired 这个是是看以后的类型正如上面的AccountDao会去找它对应的实现类然而可能有多个实现类 所以要用qualifier来指定id来确定 一开始如果为accountDao变量名就不会报错 这是因为它会去依据变量名去匹配id 这两个办法是同一个线程 threadlocal key就是以后线程 value为它这个线程存储的数据能够为任何类型 这两个办法是同一个线程的 所以他们的threadlocal是同一个(同一个容器) 所以第一个放进去的连贯的容易 跟二个取出连贯的容器是同一个 所以 保障了调用这两个办法的连贯为同一个 即保障是同一个事务 remove就是清空容器 https://www.cnblogs.com/tnt-33/p/10149087.html两个动静代理的区别 罕用 最终所注入的接口对象曾经为动静代理的接口对象

October 5, 2020 · 1 min · jiezi

关于spring:SpringMVC文件的上传与下载

一、后期筹备开发环境JDK:1.8Tomcat:9.0.3编译器:IntelliJ IDEA 2019maven:3.6.3spring:5.2.8留神:肯定须要commons-fileupload和commons-io包,在maven中我曾经配置了,如果不应用Maven的能够到maven repository下来下载pom.xml配置<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> <spring.version>5.2.8.RELEASE</spring.version> <slf4j.version>1.6.6</slf4j.version> <log4j.version>2.13.3</log4j.version></properties><dependencies> <!-- spring --> <!-- beans--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <!-- core--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <!-- aop相干的技术 --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.6.8</version> </dependency> <!-- aop --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <!-- context容器 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <!-- web --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <!-- webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <!-- spring测试 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency><!-- 文件的上传与下载--> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency></dependencies> <build> <finalName>TestSSM</finalName> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging --> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.1</version> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.2.2</version> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.5.2</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> </plugins> </pluginManagement> </build>二、上传与下载文件的上传须要在spring中配置一个文件解析器<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 开启spring注解驱动--> <context:component-scan base-package="com.cjh"/> <!-- 开启mvc注解驱动--> <mvc:annotation-driven></mvc:annotation-driven> <!-- 配置文件解析器--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 配置上传文件的大小--> <property name="maxUploadSize" value="20480000"/> </bean></beans>JSP:<%@ page contentType="text/html; charset=UTF-8" language="java" %><html><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>cai jin hong</title></head><body> <form action="upload.do" method="post" enctype="multipart/form-data"> <input type="text" name="text" value=""> <input type="file" name="upload" value=""> <input type="submit" value="submit"> </form></body></html>具体Controller类:@Controllerpublic class UserController { //文件的上传 /** * @param text 类型为text的input标签输入框内容,与input标签的name属性的名字统一 * @param upload 文件对象,与类型为file的input标签中的name属性的名字统一 * @return //跳转到一个新的页面 * @throws IOException */ @RequestMapping("upload.do") public String upload(String text, MultipartFile upload) throws IOException { System.out.println(text); //获取文件名字 String fileName = upload.getOriginalFilename(); //传输到指定地位 upload.transferTo(new File("D://test//", fileName)); return "welcome.jsp"; }}文件的下载JSP:<%@ page contentType="text/html; charset=UTF-8" language="java" %><html><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>cai jin hong</title></head><body> <a href="download.do?fileName=订单列表.xls">文件下载</a></body></html>具体的Controller类:@Controllerpublic class UserController { //文件的下载 @RequestMapping("download.do") public ResponseEntity<byte[]> upload(String fileName) throws IOException { System.out.println("fileName:" + fileName); //获取文件对象 File file = new File("D://test//" + fileName); //解决中文字符集 // fileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1"); //设置响应头信息 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); headers.setContentDispositionFormData("attachment", fileName); byte[] b = FileUtils.readFileToByteArray(file); return new ResponseEntity(b, headers, HttpStatus.CREATED); }}

October 4, 2020 · 2 min · jiezi

关于spring:SpringMVC拦截器

后期常识拦截器的作用:拦截器的作用是在服务器解决申请资源之前、之后去做一些事件,比方在解决申请资源之前须要验证一下从前端传入过去的数据合不合规定,解决申请资源之后验证一下有没有产生异样拦截器的三个办法: preHandle:在解决申请资源之前做的办法 当返回值为true,示意放行,也就是能够解决申请资源当返回值为false,示意不放行,也就是不能解决申请资源postHandle:在解决申请资源之后做的办法,如果preHandle不放行,那么这个办法也肯定不会执行到afterCompletion:是一个最终执行的办法,如果是只有一个拦截器可能看不到成果,然而当有多个拦截器时,会先执行多个拦截器的preHandle和postHandle,而后再执行afterCompletion拦截器与filter的触发地位: filter:在咱们应用Tomcat的时候,它给咱们提供了filter过滤器,这个filter的触发地位是位于浏览器和服务器之间,也就是当申请的资源还没达到服务器时,filter就先对申请的资源做解决拦截器:而拦截器是SpringMVC框架提供的,既然是框架提供的,那么当申请还没达到服务器时SpringMVC是没有方法解决的,也就是当SpringMVC接管到申请之后,它会先把申请资源交给拦截器,而后再放行给解决具体申请资源的Servlet类拦截器与filter的拦挡范畴 filter:什么都可能拦挡,既能拦挡Servlet资源,也能拦挡html,css,jsp等文件拦截器:只能拦挡Servlet资源一、拦截器的配置与应用自定义拦截器类 public class MyInterceptor implements HandlerInterceptor { //事后解决,在资源解决前 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("interceptor1:资源解决前"); return true;//放行 } //后置解决,在资源解决后 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("interceptor1:资源解决后"); } //最终实现后处理 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("interceptor1:最终办法"); } }Controller执行类 @Controllerpublic class UserController { @RequestMapping("testIntercept.do") public String testIntercept(){ System.out.println("controller资源解决了"); return ""; }}JSP ...

October 4, 2020 · 1 min · jiezi

关于spring:SpringMVC异常的处理

应用场景:当浏览器向浏览器发送申请,而服务器解决申请呈现了异样的状况,如果间接把错误信息给浏览器展现进去是很不好的,因为用户就能看到具体的代码错误信息。所以当出现异常状况时,服务器能够给用户一个本次申请异样的页面,让用户晓得以后服务器有点问题,请稍后再试。 实现流程1)自定义异样类public class MyException extends RuntimeException{ private String message; public MyException(){} public MyException(String message){ this.message = message; } public void setMessage(String message) { this.message = message; } @Override public String getMessage() { return message; }}2)自定义异样解决类,解决咱们抛出的异样 对于异样的解决,我是把它转发到一个error页面,这里大家能够本人创立一个@Componentpublic class ExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { if (e instanceof MyException){ ModelAndView mv = new ModelAndView(); mv.addObject("errorMessage", e.getMessage()); mv.setViewName("error.jsp"); return mv; } return null; }}Controller类:这里是捕捉了一个空指针异样,而后抛出了咱们自定义的异样@Controllerpublic class UserController { @RequestMapping("testException.do") public String testException(){ try { String str = null; str.length(); }catch (NullPointerException e){ e.printStackTrace(); throw new MyException("服务器忙碌,请稍后再试!!!"); } return "testException.jsp"; }}ApplicationContext.xml(Spring外围配置文件)配置信息如下:<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 开启spring注解驱动--> <context:component-scan base-package="com.cjh"/><!-- 开启mvc注解驱动--> <mvc:annotation-driven></mvc:annotation-driven></beans>

October 3, 2020 · 1 min · jiezi

关于spring:悟空CRM110介绍

悟空CRM-11.0悟空CRM介绍演示地址:http://www.5kcrm.com 下载地址:https://gitee.com/wukongcrm 注:悟空CRM采纳全新的前后端拆散模式,本仓库代码中已集成前端vue打包后文件,可免去打包操作。如需调整前端代码,请独自下载前端代码悟空CRM目录构造wk_crm├── admin -- 系统管理模块和用户治理模块├── authorization -- 鉴权模块,目前仅用于登录鉴权,前期可能有更改├── bi -- 商业智能模块├── core -- 通用的代码和工具类├── crm -- 客户治理模块├── gateway -- 网关模块├── job -- 定时工作模块├── oa -- OA模块└── work -- 项目管理模块悟空CRM应用的次要技术栈名称版本阐明spring-cloud-alibaba2.2.1.RELEASE(Hoxton.SR3)外围框架swagger2.9.2接口文档mybits-plus3.3.0ORM框架sentinel2.2.1.RELEASE断路器以及限流nacos2.2.1.RELEASE注册核心以及分布式配置管理seata1.2.0分布式事务elasticsearch2.2.5.RELEASE(6.8.6)搜索引擎中间件jetcache2.6.0分布式缓存框架xxl-job2.1.2分布式定时工作框架gateway2.2.2.RELEASE微服务网关feign2.2.2.RELEASE服务调用悟空CRM我的项目架构图 应用阐明一、前置环境Jdk1.8Maven3.5.0+Mysql5.7.20 (数据库装置注意事项)Redis(版本不限)Elasticsearch 6.8.6 (环境配置注意事项)Seata(1.2.0)(配置阐明)Sentinel(1.7.2)(我的项目中sentinel应用8079端口)Nacos(1.2.1)二、装置阐明1. 导入初始化sql,目前我的项目下gateway模块应用的独立数据库,其余模块应用同一数据库- 初始化gateway模块数据库:新建数据库 `nacos` 在`nacos`数据库中运行` DB/config_info_route.sql`- 初始化其余模块数据库:新建数据库 `wk_crm_single` 在`wk_crm_single`数据库中运行 `DB/wk_crm_single.sql`- 初始化定时工作模块数据库:新建数据库 `xxl_job` 在`xxl_job`数据库中运行 `DB/xxl_job.sql`- 初始化seata数据库:新建数据库 `seata` 在`seata`数据库中运行 `DB/seata.sql`2.在我的项目根目录执行mvn install3.在各个模块下resource目录配置数据库帐号信息以及redis帐号信息(默认应用的是application-dev.yml配置文件,打包后启动脚本默认应用的application-test.yml配置文件)4.在crm\src\main\resources\application-dev.yml外面批改elasticsearch配置spring.elasticsearch.rest.uris = elasticsearch地址 例:127.0.0.1:9200spring.elasticsearch.rest.username = elasticsearch用户名 例:elastic 无明码可留空spring.elasticsearch.rest.password = elasticsearch明码 例: password 无明码可留空5.(可选)批改零碎中文件上传地址,默认为本地配置,本地上传还需配置公网地址,指向服务器网关crm.upload.config:1 文件上传配置 1:本地 2:阿里云OSS crm.upload.oss oss上传文件所需配置内容 crm.upload.oss.bucketName 须要配置两个bucket,0为登录才可拜访文件上传地址,1为齐全公开文件上传地址crm.upload.local 本地上传文件所需配置内容 crm.upload.local.uploadPath 须要配置两个地址0为登录才可拜访文件上传地址,1为齐全公开文件上传地址6.(可选)批改jetcache缓存配置详见 官网文档7.(可选)我的项目日志文件在core\src\main\resources\logback-spring.xml批改8. 我的项目打包部署·在我的项目根目录下执行 mvn clean -Dmaven.test.skip=true package·而后把对应模块下target文件夹下·${name}-${version}-SNAPSHOT.zip/tar.gz上传到服务器,例:admin-0.0.1-SNAPSHOT.zip 并将压缩文件解压,查看对应配置文件。9. 我的项目启动 <br/>先启动nacos,seata,sentinel, elasticsearch,mysql,redis等根底服务在第八步解压的文件模块下通过执行`sh 72crm.sh start`(windows下间接运行72crm.bat)启动各个模块服务。其中我的项目根底模块:gateway,authorization,admin必须启动,其余模块可按需启动。启动实现后,在浏览器中拜访:http://localhost:8443/即可登录零碎三、其余阐明1.代码生成器及接口文档<br/>代码生成器地址:core\src\test\com\kakarote\generator\Generator.java接口文档地址`http://localhost:8443/swagger-ui.html`或者拜访对应服务下 http://服务地址:端口/swagger-ui.html2.模块依赖关系 <br/>- 除网关外,其余我的项目均依赖于admin模块,用于获取以后登录人的信息- oa模块的工作依赖于work模块,其余一些关联业务性能依赖于crm模块- 商业智能依赖crm,oa模块三、悟空CRM功能模块预览 ...

October 3, 2020 · 1 min · jiezi

关于spring:SpringMVC请求与响应的处理实战二

本篇文章讲述响应的解决,对于申请的解决能够看我第一篇文章链接地址:https://segmentfault.com/a/11... 后期筹备应用环境JDK:1.8Tomcat:9.0.3Spring:5.2.8Maven:3.6.3编译器:IntelliJ IDEA 2019web.xml配置<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <servlet-name>mvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:ApplicationContext.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>mvc</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping></web-app>ApplicationContext.xml配置(Spring外围配置文件)<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 开启spring注解驱动--> <context:component-scan base-package="com.cjh"/> <!-- 开启mvc注解驱动--> <mvc:annotation-driven></mvc:annotation-driven></beans>响应解决原生的Servlet解决有间接采纳response获取输入流间接响应会给浏览器,通过request转发或者重定向三种形式,当初应用spring-mvc进行响应的解决 返回String"forward:资源路径名":转发到冒号前面的资源门路"redirect:资源路径名":重定向到冒号前面的资源路径名"":如果返回的是空串,则会找index.jsp资源示例代码如下:@Controllerpublic class UserController { //办法中传入实体对象:对象外面有list汇合 @RequestMapping("test.do") public String testFive(User user){ System.out.println(user); return "redirect:welcome.jsp"; }}ModelAndViewModel、ModelMap和ModelAndView的区别 Model和ModelMap只能存储返回的参数(key-value)ModelAndView既能存储返回的参数,也能存储资源门路ModelAndView中有两个重要的属性: Object view:存储资源门路ModelMap model:存储返回的参数,mvc框架会将存储的Key-value数据存入request作用域代码如下: index.jsp:<%@ page contentType="text/html; charset=UTF-8" language="java" %><html><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>cai jin hong</title></head><body> <form action="test.do" method="post"> account:<input type="text" name="account" value=""><br> password:<input type="text" name="password" value=""><br> balance:<input type="text" name="balance" value=""><br> address1:<input type="text" name="addressList[0].address" value=""><br> address2:<input type="text" name="addressList[1].address" value=""><br> <input type="submit" value="submit"> </form></body></html>welcome.jsp:(这时候,Jsp就能从requestScope作用域外面提取到咱们存进去的account)<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head> <title>Title</title></head><body> param:welcome,${param.account}<br> requestScope:welcome,${requestScope.account}<br></body></html>Java:@Controllerpublic class UserController { //办法中传入实体对象:对象外面有list汇合 @RequestMapping("test.do") public ModelAndView testFive(User user){ //创立ModelAndView对象 ModelAndView mv = new ModelAndView(); //设置返回的参数 mv.addObject("account", user.getAccount()); mv.addObject("password", user.getBalance()); //设置返回门路 mv.setViewName("welcome.jsp"); return mv; }}存入Session作用域首先,须要将参数(Key-value)存入request作用域而后通过@SessionAttributes({"key",""})注解存入Session作用域代码如下:(此时,welcome.jsp就能从SessionScope作用域里获取到account的值)@Controller@SessionAttributes("account")public class UserController { //办法中传入实体对象:对象外面有list汇合 @RequestMapping("test.do") public ModelAndView testFive(User user){ //创立ModelAndView对象 ModelAndView mv = new ModelAndView(); //设置返回的参数 mv.addObject("account", user.getAccount()); mv.addObject("password", user.getBalance()); //设置返回门路 mv.setViewName("welcome.jsp"); return mv; }}

October 3, 2020 · 1 min · jiezi

关于spring:SpringMVC请求与响应的处理实战三

本篇文章讲述对JSON数据的解决,对于响应的解决能够看我第二篇文章链接地址:https://segmentfault.com/a/11... 后期筹备应用环境JDK:1.8Tomcat:9.0.3Spring:5.2.8Maven:3.6.3编译器:IntelliJ IDEA 2019web.xml配置<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <servlet-name>mvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:ApplicationContext.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>mvc</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping></web-app>ApplicationContext.xml配置(Spring外围配置文件)<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 开启spring注解驱动--> <context:component-scan base-package="com.cjh"/> <!-- 开启mvc注解驱动--> <mvc:annotation-driven></mvc:annotation-driven></beans>JSON数据的解决浏览器通过ajax发送JSON数据点击button,发送JSON数据 <%@ page contentType="text/html; charset=UTF-8" language="java" %><html><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>cai jin hong</title> <script type="text/javascript"> window.onload = function () { document.getElementById("button").onclick = function () { //1、创立一个AJAX对象 var xhr = new XMLHttpRequest(); xhr.open("POST", "test.do", true); //告知浏览器发送的是什么信息 xhr.setRequestHeader("Content-type", "application/json;charset=UTF-8"); //2、随时监听响应回来的数据 xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200){ alert(xhr.responseText); } } //3、发送JSON数据 xhr.send('{"account":"2020", "password": "123456", "balance":98}'); } } </script></head><body> <button id="button">测试JSON数据</button></body></html>服务器接管JSON数据留神:须要引入jackson-core、jackson-databind和jackson-annotations包应用@RequestBody注解,表明接管的参数是JSON格局的,如果发送的JSON对象的key名字刚好是实体对象的属性名字,那么只有咱们的办法参数写的是实体对象类型,mvc会包装成咱们要求的类型代码如下:@Controllerpublic class UserController { //办法中传入实体对象:对象外面有list汇合 @RequestMapping("test.do") public void testFive(@RequestBody User user){ System.out.println(user); }}服务器响应JSON数据留神:须要引入jackson-core、jackson-databind和jackson-annotations包响应实体对象:应用@ResponseBody注解,间接返回实体对象(mvc会把它转换成JSON格局的数据) ...

October 3, 2020 · 1 min · jiezi

关于spring:SpringMVC请求与响应的处理实战一

后期筹备应用环境JDK:1.8Tomcat:9.0.3Spring:5.2.8Maven:3.6.3编译器:IntelliJ IDEA 2019web.xml配置<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <servlet-name>mvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:ApplicationContext.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>mvc</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping></web-app>ApplicationContext.xml配置(Spring外围配置文件)<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 开启spring注解驱动--> <context:component-scan base-package="com.cjh"/> <!-- 开启mvc注解驱动--> <mvc:annotation-driven></mvc:annotation-driven></beans>申请1. 申请的发送与接管以下写的浏览器和服务器的形式是绝对应的,比方第一种申请就对应着第一种接管 1)浏览器发送申请的形式: 第一种:申请资源名(找的是具体的解决类),申请的办法上写上@RequestMapping注解 这种模式要求申请的解决类下只有一个办法第二种:申请资源名?method=具体执行办法(找的是具体的解决类中的办法)第三种:申请资源名(找的是具体的执行办法)-----罕用留神:还有一种是通过ajax发送JSON格局的数据,这会放到第三篇文章中去讲2)服务器接管申请的形式: 不论是对应浏览器的哪种发送形式,都须要应用@RequestMapping注解第一种:在类上写上@RequestMapping(申请资源名)注解第二种:在类上写上@RequestMapping(申请资源名)注解,在办法上也要写上@RequestMapping(params = {method=办法名})注解(method也能够换成其余名字)第三种:间接在办法上写上@RequestMapping(申请资源名)3)@RequestMapping注解中的其余办法 path/value:用来存储申请资源名params:要求浏览器必须发送的参数,参数的模式是{"key=value",""},method:要求浏览器申请的办法(GET/POST)headers:要求浏览器必须携带的申请头({"Accept-Language",""})留神:前面三个一旦写明,就是要求浏览器必须携带的货色,如果没有携带,那么服务器是不解决的4)具体示例代码: 第一种形式: JSP<%@ page contentType="text/html; charset=UTF-8" language="java" %><html><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>cai jin hong</title> <style> </style></head><body> <a href="userController.do">测试第一种申请形式</a></html>java@Controller@RequestMapping("userController.do")public class UserController { @RequestMapping public void testOne(){ System.out.println("test办法执行了"); }}测试后果:浏览器显示404,服务器控制台打印出test办法执行了第二种形式: ...

October 3, 2020 · 5 min · jiezi

关于spring:SpringMVC中文字符集处理自定义转换器

中文字符集的解决解决中文字符集应用mvc提供的一个CharacterEncodingFilter过滤器,只须要在web.xml配置信息外面增加如下过滤器配置 <filter> <filter-name>characterEncoding</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <!-- 配置字符集--> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param></filter><filter-mapping> <filter-name>characterEncoding</filter-name> <url-pattern>/*</url-pattern></filter-mapping>自定义类型转换器情景案例:咱们须要在网页上输出一个日期,然而springmvc有本人的日期转换格局类型,然而咱们想用咱们本人的格局,这时候就须要自定义一个类型转换器 1)自定义一个类,实现Converter接口,重写办法/** * 自定义转化器:将String转化成Date */public class StringToDateConverter implements Converter<String, Date> { @Override public Date convert(String s) { //自定义一个转换规则 //将申请发送过去的String信息转化成本人要的那个对象 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh-mm-ss"); Date date = null; try { date = sdf.parse(s); } catch (ParseException e) { e.printStackTrace(); } //将对象返回 return date; }}2)告知Spring须要加载并治理该对象,Spring的外围配置文件信息如下:<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 开启spring注解驱动--> <context:component-scan base-package="com.cjh"/><!-- 开启mvc注解驱动--> <mvc:annotation-driven></mvc:annotation-driven><!-- 加载一个类型转换器,这个类是用来帮咱们治理咱们自定义的类型转换器--> <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="com.cjh.util.StringToDateConverter"/> </set> </property> </bean><!-- 手动配置这个类的驱动--> <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven></beans>3)具体实现如下: ...

October 3, 2020 · 1 min · jiezi

关于spring:手把手教你搭建SSM框架Eclipse版

手把手教你搭建SSM框架(Eclipse版)本期文章欲带大家实现SSM(Spring+SpringMVC+MyBatis)框架的Web我的项目,通常也称为三大框架做整合。在开始教程之前,先来了解下SSM的概念。 原文来自集体公众号【C you again】,若有须要,请在公众号后盾私信!! Spring就像是整个我的项目中拆卸Bean的大工厂,在配置文件中能够指定应用特定的参数去调用实体类的构造方法来实例化对象,它有两个外围别离是IOC(管制反转)和AOP(面向切面编程)。IOC意为管制反转,简略的了解就是将应用new关键字创建对象的权力交给Spring框架来治理,开发者更专一于业务逻辑的实现。AOP意为面向切面编程,通过预编译形式和运行期间动静代理实现程序性能的对立保护的一种技术,利用AOP能够对业务逻辑的各个局部进行隔离,从而使得业务逻辑各局部之间的耦合度升高,进步程序的可重用性,同时进步了开发的效率,事务管理、日志文件打印通常都会用到AOP。 SpringMVC是Spring框架的一个模块,是一个基于MVC的Web框架,能够说它是前后端数据传输的桥梁。 MyBatis是一款优良的长久层框架,它反对定制化SQL、存储过程以及高级映射。MyBatis防止了简直所有的JDBC代码和手动设置参数以及获取后果集,能够应用简略的XML或注解来配置和映射原生信息,将接口和Java的 Pojo(Plain Ordinary Java Object,一般的Java对象)映射成数据库中的记录。 好了,看完以上概念,咱们就正式开始明天的教程了。制作不易,多多转发分享哦!! 1、新建动静Web我的项目本教程用到Eclipse开发工具,所以JDK、开发工具都是要提前装置配置好的。 File-->New-->Project-->Dynamic Web Project 输出项目名称(本教程我的项目名:ssmDemo),最初点击Finish即可。 2、补充、欠缺我的项目目录为使得我的项目合乎MVC开发标准,咱们须要在src下新建controller、service、mapper、entity几个包和resources目录。实现后目录构造如下图: 3、导入所需Jar包如果你装置了Maven插件,导入Jar包的事件就交给它去做了,你只须要退出相干依赖即可。本期教程用最原始的办法导入我的项目所需Jar包。手动导入会存在Jar包版本抵触等很多问题,倡议间接下载应用,下载地址在公众号【C you again】后盾回复“Jar”自行下载,若不能失常下载,请在后盾私信。 首先将下载好的Jar包复制到WebContent-->WEB-INF-->lib文件夹下,而后选中所有Jar包-->鼠标右击-->Build Path-->Add to Build Path。 4、增加相干配置文件实现以上根本步骤后,接下来就是SSM整合的关键步骤了。 首先在我的项目的WebContent-->WEB-INF下的web.xml文件中退出以下配置,如果没有web.xml文件就须要本人新建一个。 <?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <welcome-file-list> <welcome-file>test.jsp</welcome-file> </welcome-file-list> <!-- 加载spring容器 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:application.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 解决post乱码 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>springMvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springMvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping></web-app>实现web.xml的配置后,在后面建好的resources文件夹下新建application.xml,具体解释看文件外部。 ...

October 3, 2020 · 3 min · jiezi

关于spring:SpringMVC请求与响应的处理实战一

后期筹备应用环境JDK:1.8Tomcat:9.0.3Spring:5.2.8Maven:3.6.3编译器:IntelliJ IDEA 2019web.xml配置<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <servlet-name>mvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:ApplicationContext.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>mvc</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping></web-app>ApplicationContext.xml配置(Spring外围配置文件)<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 开启spring注解驱动--> <context:component-scan base-package="com.cjh"/> <!-- 开启mvc注解驱动--> <mvc:annotation-driven></mvc:annotation-driven></beans>申请1. 申请的发送与接管以下写的浏览器和服务器的形式是绝对应的,比方第一种申请就对应着第一种接管 1)浏览器发送申请的形式: 第一种:申请资源名(找的是具体的解决类),申请的办法上写上@RequestMapping注解 这种模式要求申请的解决类下只有一个办法第二种:申请资源名?method=具体执行办法(找的是具体的解决类中的办法)第三种:申请资源名(找的是具体的执行办法)-----罕用2)服务器接管申请的形式: 不论是对应浏览器的哪种发送形式,都须要应用@RequestMapping注解第一种:在类上写上@RequestMapping(申请资源名)注解第二种:在类上写上@RequestMapping(申请资源名)注解,在办法上也要写上@RequestMapping(params = {method=办法名})注解(method也能够换成其余名字)第三种:间接在办法上写上@RequestMapping(申请资源名)3)@RequestMapping注解中的其余办法 path/value:用来存储申请资源名params:要求浏览器必须发送的参数,参数的模式是{"key=value",""},method:要求浏览器申请的办法(GET/POST)headers:要求浏览器必须携带的申请头({"Accept-Language",""})留神:前面三个一旦写明,就是要求浏览器必须携带的货色,如果没有携带,那么服务器是不解决的4)具体示例代码: 第一种形式: JSP<%@ page contentType="text/html; charset=UTF-8" language="java" %><html><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>cai jin hong</title> <style> </style></head><body> <a href="userController.do">测试第一种申请形式</a></html>java@Controller@RequestMapping("userController.do")public class UserController { @RequestMapping public void testOne(){ System.out.println("test办法执行了"); }}测试后果:浏览器显示404,服务器控制台打印出test办法执行了第二种形式: ...

October 3, 2020 · 5 min · jiezi

关于spring:SpringMVC配置与使用

SpringMVC是Spring的一个组件,所以咱们在应用SpringMVC的时候也会应用到Spring 应用环境JDK:1.8Tomcat:9.0.3spring:5.2.8编译器:IDEA20191、导包须要引入Spring-web和Spring-webmvc两个包,能够到maven仓库外面去下载或者应用maven依赖 2、ApplicationContext.xml配置(Spring的外围配置文件)ApplicationContext.xml文件须要放在WEB-INF下,并且须要把名字改为拦挡的serlvet-name+ -Servlet,比方我这边的拦挡名字为mvc,所以我须要把配置文件名改为mvc-Servlet.xml如果不放在WEB-INF下,须要在web.xml文件中进行门路配置(如下web.xml文件中的init-param标签配置)留神命名空间的问题<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 开启spring注解驱动--> <context:component-scan base-package="com.cjh"/> <!-- 开启mvc注解驱动--> <mvc:annotation-driven></mvc:annotation-driven></beans>3、web.xml配置<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <servlet-name>mvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <!-- 阐明Spring外围配置文件的地位--> <param-value>classpath:ApplicationContext.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>mvc</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping></web-app>4、java的实现Controller类@Controller@RequestMapping("userController.do")public class UserController { public UserController(){ System.out.println("controller创立了"); } @RequestMapping public void test(){ System.out.println("controller:test办法执行了"); } }index.jsp<%@ page contentType="text/html; charset=UTF-8" language="java" %><html><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>cai jin hong</title> <style> </style></head><body> <a href="userController.do">测试</a></body></html>申请和响应流程: 当点击测试超链接时,浏览器向服务器发送userController.do的资源申请服务器接管到之后,找到类下面带有@RequestMapping("userController.do")注解的对象找到了之后,查找办法下面带有@RequestMapping("xxx")注解的办法 如果只有一个办法,能够不必写名字,间接写RequestMapping如果有多个办法,须要注明办法名找到了之后,执行办法,并将解决信息响应回给浏览器(该代码中没有返回值)本篇文章只讲了一下最根本的时候,下一篇文章会具体的说的SpringMVC申请和响应的解决!!!

October 2, 2020 · 1 min · jiezi

关于spring:Spring基于注解开发

Spring罕用注解@Component 作用:告知Spring帮咱们治理这个对象搁置地位:类上@Controller、@Service、@Repository 作用:与Component搁置地位:类上这样写更能体现出分层架构的思维,@Controller注解用于管理控制层的对象,@Service注解用于治理model层中的service层的对象,@Repository用于治理model层中的dao层的对象@Autowired 作用:主动拆卸搁置地位:属性上、构造方法上、set办法上@Qualifier 作用:配合Autowired应用,用来指定具体注入的对像的惟一标识@Resource(name="") 等同于Autowired和Qualifier的联合应用它不是Spring框架的注解@Scope 作用:申明对象的作用域,singletonprototype搁置地位:类上@Lazy 作用:申明该对象是否启用懒加载机制搁置地位:类上@Value() 作用:给属性注入值搁置地位:属性上@PostConstruct 作用:当对象实例化之后,第一次执行的办法@PreDestroy 作用:当对象被销毁后,第一次执行的办法@Bean 作用:通过办法产生一个对象交给Spring去治理搁置地位:办法下面@Configuration 作用:申明该类是Spring的外围配置类(等同于Spring的外围配置文件),搁置地位:类下面@ComponentScan 作用:告知Spring哪些包是须要扫描的(扫描须要被Spring治理的对象)搁置地位:类下面@PropertySource 作用:引入一个内部.properties文件搁置地位:类下面@Import 作用:引入其余配置类搁置地位:类下面注解的应用1)如何用注解代替外围配置文件 自定义一个配置类@Configuration @ComponentScan(basePackages = {"com.cjh"})//通知Spring要扫描包的地位@Import(ConfigClass.class)//引入其余配置类public class MainConfig {}2)如何引入properties文件以及动静的注入值//classpath:+文件名,告知Spring文件名@PropertySource("classpath:jdbc.properties")public class ConfigClass {//主动注入属性值,采纳SPEL表达式,获取properties文件的配置信息 @Value("${driverClassName}") private String driverClassName; @Value("${url}") private String url; @Value("${user}") private String username; @Value("${password}") private String password; //通过@bean注解,告知spring以下两个办法是要生成对象的办法,并让spring治理 @Bean public JdbcTemplate jdbcTemplate(DataSource dataSource){ return new JdbcTemplate(dataSource); } @Bean public DataSource dataSource(){ DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/bank?serverTimezone=CST"); dataSource.setUsername("root"); dataSource.setPassword("123456"); return dataSource; }}jdbc.properties文件内容driverClassName=com.mysql.cj.jdbcurl=jdbc:mysql://localhost:3306/bank?serverTimezone=CSTuser=rootpassword=1234563)如何让Spring帮咱们治理对象@Service //告知Spring,UserService对象须要治理,也能够应用Componentpublic class UserService { }4)管理机制问题(作用域、懒加载)@Controller@Scope(value = "singleton") //告知Spring这个对象是单例的@Lazy //告知Spring开启懒加载public class UserController { }5)主动拆卸@Controller@Scope(value = "singleton")@Lazypublic class UserController { //告知Spring这个属性须要主动拆卸 @Autowired UserService userService; public UserController(){ System.out.println("controller创立了"); } public UserController(UserService userService){ this.userService = userService; } public void setUserService(UserService userService) { this.userService = userService; }}对象实例化后以及被销毁后执行的办法@Servicepublic class UserService { private UserDao userDao; public UserService(){ System.out.println("service创立了"); } public UserService(UserDao dao){ this.userDao = dao; } //告知Spring,getMessage这个办法在userService对象实例化之后以及被销毁之后都要执行 @PostConstruct @PreDestroy public void getMessage(){ System.out.println("hhhh"); } @Autowired public void setUserDao(UserDao userDao) { this.userDao = userDao; } public UserDao getUserDao() { return userDao; }}

October 2, 2020 · 1 min · jiezi

关于spring:Spring定时器的使用

原生的Java定时器应用Java.util包下的定时器也很简略,具体代码如下: //设置定时器开始工夫Date time = sdf.parse("2020-10-01 16:40:00");//设置定时器Timer timer = new Timer();//第三个参数示意每隔多久循环一次timer.schedule(new TimerTask() { @Override public void run() { System.out.println("嗨"); }}, time, 3000);Spring的定时器1)导包,除了spring提供的包之外,还须要quartz包(能够到maven仓库中去下载)2)自定义Task类: 当定时器启动时,Spring执行咱们指定Task中的办法3)MethodInvokingJobDetailFactoryBean类: 将自定义的Task类交给MethodInvokingJobDetailFactoryBean,并通知它Task的执行办法,由它负责去执行4)CronTriggerFactoryBean触发器: 定义定时器触发的工夫,以及执行对象5)SchedulerFactoryBean: 将触发器对象交给它对立保存配置信息如下:<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd "><!-- 定时器--> <bean id="myTask" class="com.cjh.MyTask"></bean> <!-- 创立一个Spring提供好的计时器对象,用来做倒计时管控--> <bean id="taskExecutor" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="myTask"/> <property name="targetMethod" value="test"/> </bean> <!-- 触发器--> <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="taskExecutor"/> <property name="cronExpression" value="30/5 41 18 * * ?"/> </bean> <!-- 治理触发器对象的容器--> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="cronTrigger"/> </list> </property> </bean></beans>6)主函数 只须要加载配置文件,触发器就会启动public class TestMain { public static void main(String[] args) throws MessagingException, ParseException { ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); }}

October 1, 2020 · 1 min · jiezi

关于spring:SpringEmail的使用

一、应用Mail.jar包发送邮件首先先介绍如何应用Mail.jar包发送邮件,这里须要去下载mail.jar包导入进以后工程,能够去maven仓库外面查找下载,代码如下: public class TestMain { public static void main(String[] args) throws MessagingException { //1、下载一个mail.jar //2、导包 //3、创立一个用于寄存配置信息的对象 Properties prop = new Properties(); //4、设置发送邮件须要的一些信息 //设置发送邮件的协定 prop.put("mail.transport.protocol", "smtp"); //设置发送邮件的主机名 prop.put("mail.smtp.host", "smtp.qq.com"); //设置发送邮件的端口,默认25,可不写 // prop.put("mail.smtp.port", "xx"); //设置发送邮件时,是否须要进行身份认证,可不写 // prop.put("mail.smtp.auth", "true"); //设置是否应用ssl平安连贯 prop.put("mail.smtp.ssl.enable", "true"); //5、创立一个Session对象(在Java和邮箱之间建设一个连贯) Session session = Session.getDefaultInstance(prop); //6、通过session对象获取一个Transport对象(能够了解为一个输入流) Transport transport = session.getTransport(); //7、获取邮件服务器的认证 //user:发件人的邮箱 //password:发件人的认证码 String user = "cing_self0731@qq.com"; String password = "ufhannqpmjvdccbi"; transport.connect(user, password); //8、创建对象和邮件的映射 关系 Message message = createMessage(session); //9、发送邮件 //第二个参数是获取所有收件人的地址 transport.sendMessage(message, message.getAllRecipients()); //10、敞开通道 transport.close(); } //创立一个邮件对象 //参数:一个Session(连贯对象) //返回值:邮件对象(映射) MimeMessage private static Message createMessage(Session session) throws MessagingException { //1、创立一个邮件对象 Message message = new MimeMessage(session); //2、设置邮件信息 //1)设置发送人 message.setFrom(new InternetAddress("cing_self0731@qq.com")); //2)设置接管人 //参数: // 收件人类型 //To:收件人 //CC:抄送人 //BCC:密送 //收件人地址 message.setRecipient(Message.RecipientType.TO, new InternetAddress("cing_self0731@qq.com")); //3)设置发送工夫 //这里用的是以后工夫 message.setSentDate(new Date()); //4)设置邮件主题 message.setSubject("邮件主题"); //5)设置邮件注释 message.setText("邮件注释"); //保留以上设置 message.saveChanges(); return message; }}上述代码中波及到一个邮箱服务器的认证码,获取步骤如下(我这里用的是QQ邮箱): ...

October 1, 2020 · 1 min · jiezi

关于spring:SpringJDBC

最近学了一下Spring的JDBC框架,写一篇文章总结一下,因为不太罕用,我就简略总结一下增删改查的用法,这里是基于XML配置进行的留神:我这里应用的是本人的数据库,请将配置信息里的datasource数据源信息以及sql语句改成本人的电脑上的 domain实体类public class User { private String account; private String password; private Float balance; public User(String account, String password, Float balance) { this.account = account; this.password = password; this.balance = balance; } public User(){} @Override public String toString() { return "User{" + "account='" + account + ''' + ", password='" + password + ''' + ", balance=" + balance + '}'; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Float getBalance() { return balance; } public void setBalance(Float balance) { this.balance = balance; }}dao层的类public class TestJDBC { //数据源:在配置文件中配置,通过Spring主动注入 private DataSource dataSource; //调用增删改查的执行者 private JdbcTemplate jdbcTemplate; public TestJDBC(){} //初始化 public TestJDBC(DataSource dataSource){ this.dataSource = dataSource; jdbcTemplate = new JdbcTemplate(this.dataSource); } public void insert(User user){ //通过?代替传递进去的参数,必须和update办法传进去的参数程序统一 String sql = "insert into atm values(?, ?, ?)"; jdbcTemplate.update(sql, user.getAccount(), user.getPassword(), user.getBalance()); } public void delete(String account){ String sql = "delete from atm where account = ?"; jdbcTemplate.update(sql, account); } public void update(User user){ String sql = "update atm set account = ?, password = ?, balance = ? where account = ?"; jdbcTemplate.update(sql, user.getAccount(), user.getPassword(), user.getBalance(), user.getAccount()); } //查问一条记录 public User selectOne(String account){ //通过策略模式,将查问的后果包装成User对象 String sql = "select * from atm where account = ?"; return jdbcTemplate.queryForObject(sql, new RowMapper<User>(){ @Override public User mapRow(ResultSet resultSet, int i) throws SQLException { String account = resultSet.getString("account"); String password = resultSet.getString("password"); Float balance = resultSet.getFloat("balance"); return new User(account, password, balance); } }, account); } //查问多条记录 public List<User> selectList(){ String sql = "select *from atm"; //query办法依据该办法的返回值类型,将所有记录包装成List对象,而策略模式是将每一行记录包装成User对象 return jdbcTemplate.query(sql, new RowMapper<User>() { @Override public User mapRow(ResultSet resultSet, int i) throws SQLException { String account = resultSet.getString("account"); String password = resultSet.getString("password"); Float balance = resultSet.getFloat("balance"); return new User(account, password, balance); } }); }}配置信息<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"><!-- JDBC--> <bean id="userJdbcTemplate" class="com.cjh.dao.TestJDBC" autowire="constructor"></bean> <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/bank?serverTimezone=CST"/> <property name="username" value="root"/> <property name="password" value="123456"/> </bean></beans>主函数调用public class TestMain { public static void main(String[] args) { System.out.println(userDao.selectUserByAccount("2018")); ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); TestJDBC testJDBC = (TestJDBC) context.getBean("userJdbcTemplate"); //testJDBC.insert(new User("0000", "0000", 999.0f)); //testJDBC.insert(new User("0001", "0000", 999.0f)); //testJDBC.delete("0000"); //testJDBC.update(new User("0001", "1234", 999.0f)); System.out.println(testJDBC.selectList()); }}

October 1, 2020 · 2 min · jiezi

关于spring:lateinit-property-xx-has-not-been-initialized错误

1 问题形容用Kotlin编写Spring Boot,在业务层中应用@Transactional+@Autowired时呈现如下谬误: lateinit property dao has not been initialized 出错代码如下: 2 解决办法因为Kotlin类默认是final的,加上@Transactional后编译器提醒须要open: 然而加上open后没用,因而把@Transactional去掉后发现不会报错: 因而狐疑是@Transactional的问题,因为须要在类上加上open,所以尝试性地在对应的办法下面也加上open: 问题失去解决。 3 起因因为@Transactional实际上是通过反射获取Bean的注解信息,利用AOP实现的,而在Kotlin中应用AOP须要在类或办法上加上open。

September 29, 2020 · 1 min · jiezi

关于spring:Spring学习笔记六MyBatis集成

1 概述MyBaits是一个驰名的长久层框架,本文首先介绍了MyBatis的简略应用,接着与Spring进行整合,最初简略地应用了Generator去主动生成代码。 2 MyBatis简介MyBatis原本是Apache的一个开源我的项目——iBatis,2010年由Apaceh Software Foundation迁徙到了Google Code,并改名为MyBatis。 MyBatis是一个基于Java的长久层框架,提供的长久层框架包含SQL Maps和Data Access Objects,应用简略的XML或者注解用于配置映射,将接口和POJO映射成数据库中的记录,是一个玲珑、不便、高效、简略、间接、半自动化的长久层框架。 3 工作原理上图: 读取配置文件:mybatis-config.xml是全局MyBatis配置文件,配置了MyBatis运行环境信息加载映射文件:也就是SQL映射文件,配置了操作数据库的SQL语句结构会话工厂:通过配置文件结构会话工厂SqlSessionFactory创立会话对象:由上一步的会话工厂创立会话对象SqlSession获取MapperStatement:通过用户调用的api的Statement ID获取MapperStatement对象输出参数映射:通过Executor对MapperStatement进行解析,将各种Java根本类型转化为SQL操作语句中的类型输入后果映射:JDBC执行SQL后,借助MapperStatement的映射关系将返回后果转化为Java根本类型并返回4 MyBatis示例首先先来看一下纯MyBaits的示例,没有整合Spring,一个简略的Maven工程,我的项目构造如下: 4.1 依赖<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.5</version></dependency><dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version></dependency><!--驱动用的是MySQL,版本请自行批改--><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.21</version></dependency>Gradle: compile group: 'org.mybatis', name: 'mybatis', version: '3.5.5'compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.21'4.2 实体类@Setter@Getter@Builderpublic class User { private Integer id; private String name; @Override public String toString() { return "id:"+id+"\tname:"+name; }}4.3 映射文件新建一个叫UserMapper.xml的映射文件: <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="UserMapper"> <select id="selectById" parameterType="Integer" resultType="pers.entity.User"> select * from user where id=#{id} </select> <select id="selectAll" resultType="pers.entity.User"> select * from user </select> <insert id="insert" parameterType="pers.entity.User"> INSERT INTO `user` (`id`,`name`) VALUES (#{id},#{name}) </insert> <update id="update" parameterType="pers.entity.User"> UPDATE `user` set `name`=#{name} where id=#{id} </update> <delete id="delete" parameterType="Integer"> DELETE FROM `user` WHERE `id` = #{id} </delete></mapper>映射文件是一个XML文件,根元素为<mapper>,须要留神其中的namespace属性,调用的时候通过该namespace调用。其中的子元素示意SQL语句: ...

September 29, 2020 · 4 min · jiezi

关于spring:实现上传图片

封装VO对象 @Data@Accessors(chain = true)@NoArgsConstructor@AllArgsConstructorpublic class ImageVO { private Integer error;//谬误提醒 0程序运行失常 1.文件上传有误 private String url;//图片拜访的虚构门路 private Integer width; private Integer heigth; //设定上传失败的办法 public static ImageVO fail(){ return new ImageVO(1,null,null,null); } //胜利 public static ImageVO success(String url,Integer width,Integer heigth){ return new ImageVO(0,url,width,heigth); }}FileController层 @RequestMapping("/pic/upload")public ImageVO upload(MultipartFile uploadFile) throws IOException { return fileService.upload(uploadFile);}FileServiceImpl层 @Servicepublic class FileServiceImpl implements FileService{ //筹备一个存储图片的文件夹 private String rootpath="C:/jt"; //1.2筹备图片的汇合 private static Set<String> imageTypeSet; static { imageTypeSet=new HashSet<>(); imageTypeSet.add(".jpg"); imageTypeSet.add(".png"); imageTypeSet.add(".gif"); } /** * 校验: * 1.校验是否为图片 * 2.校验是否为歹意的程序 * 3.避免文件数量太多,分目录存储 * 4.避免文件重名 * 实现文件上传 * @param uploadFile * @return * @throws IOException */ @Override public ImageVO upload(MultipartFile uploadFile) throws IOException { //1.常见图片类型 jpg|png|gif…… //1.1获取以后图片的名称之后截取其中的类型 String fileName=uploadFile.getOriginalFilename(); int index = fileName.lastIndexOf("."); String fileType = fileName.substring(index); //转换为小写 fileType= fileType.toLowerCase(); //1.3判断图片类型是否正确 if(!imageTypeSet.contains(fileType)){ return ImageVO.fail();//图片类型不匹配 } //2.歹意校验 依据宽度/高度进行校验 //2.1利用工具API对象 读取字节信息 获取图片对象类型 try{ BufferedImage bufferedImage = ImageIO.read(uploadFile.getInputStream()); //2.2校验是否有高度和宽度 int width=bufferedImage.getWidth(); int height=bufferedImage.getHeight(); if (width==0||height==0) return ImageVO.fail(); //3.避免文件数量太多,分目录存储 //3.1 将工夫依照指定的格局要求 转化为字符串 String dateDir = new SimpleDateFormat("/yyyy/MM/dd/") .format(new Date()); //3.2拼接文件存储的目录对象 String fileDir=rootpath+dateDir; File dirFile=new File(fileDir); //3.3动态创建目录 if(!dirFile.exists()){ dirFile.mkdirs(); } //4 避免文件重名 //4.1 动静生成uuid String uuid= UUID.randomUUID().toString().replace("-",""); String realFileName=uuid+fileType; //5 实现文件上传 //5.1 拼接文件实在门路 String realFilePath=fileDir+realFileName; //5.2 封装对象 实现上传 File realFile=new File(realFilePath); uploadFile.transferTo(realFile); String url="https://img.alicdn.com/imgextra/i1/2978217349/O1CN01EwgFIG249tI2uaFx3_!!0-item_pic.jpg_430x430q90.jpg"; return ImageVO.success(url,width,height); }catch (Exception e){ e.printStackTrace(); return ImageVO.fail(); } }}

September 29, 2020 · 1 min · jiezi

关于spring:摊牌了我要手写一个Spring-Boot

目前的话,曾经把 Spring MVC 相干罕用的注解比方@GetMapping 、@PostMapping 、@PathVariable 写完了。我也曾经将我的项目开源进去了,地址:https://github.com/Snailclimb/jsoncat 。_原创开源不易,感觉不错的话,欢送给良心作者 1 个 star 激励一下!_ 明天是晴天,我像平常一样坐在窗台,看着电脑“发愣”。毕竟是周末,就不分享技术干货了。 简略和小伙伴们聊聊本人最近正在做,曾经开始做的事件。 01 重构 JavaGuide咱们常常会对本人晚期写的代码感觉恶心,这是导致很多我的项目烂尾、不好保护很重要的一个起因之一。 写作也是一样,我也常常感觉本人晚期写的文章像一坨翔。造成这个景象的起因很简略!我感觉次要可能有两方面起因: 本人积淀的常识更多,对于某个知识点的了解更加粗浅。不同于其余类型文章,技术类文章自身就须要不断完善,文章内容才会更好。所以,最近几个月我始终抽空对 JavaGuide 上晚期的一些文章进行大篇幅重构,比方 Java根底、Java汇合框架、 Zookeeper 、Redis等等。 毕竟,工夫无限,本人也还是把次要精力放在写代码上。所以,局部文章还没有开始重构,比方数据结构局部的内容。 就十分期待小伙伴们一起奉献出本人的力量啊!让 Guide哥 能多点工夫写代码,嘿嘿! 02 写了个简略的 RPC框架我在大学的时候,就应用过 Dubbo 这类 RPC 框架,对于 RPC 框架的原理也有一点的意识。 于是乎!疫情那会工作也不是很忙,我就想着说本人要不要也写一个 RPC 框架玩玩。 说做就做!前前后后花了 3 个月,我利用业余时间手写一个简略的 RPC 框架(玩具),名字叫做 guide-rpc-framework。这个框架是基于 Netty+Kyro+Zookeeper 并且整合了 Spring 来做的。 讲真!的确,破费了不少精力。尽管,这玩意的原理不难,然而,想写好的确要花工夫。 目前的话,这个我的项目曾经有 0.7k 的 star。感激小伙伴们的反对! 像这样的开源我的项目,放到简历上相对是加分项! 而且,我在本人去写 RPC 框架的时候,加深了本人对于 RPC 框架原理的意识。具体落实到代码实现的过程中,遇到了很多问题,解决问题的过程中也进步了本人的编程能力和解决问题的能力。总而言之,造轮子是一种特地可能进步本人零碎编程能力的伎俩。 03 写一个简易版的“Spring Boot”是的!我筹备开始造下一个轮子了,一个简易版的“Spring Boot”!名字我都起好了,叫做“jsoncat”。 ...

September 29, 2020 · 1 min · jiezi

关于spring:一起来读官方文档SpringIOC07

1.8。容器扩大点通常,应用程序开发人员不须要对ApplicationContext 实现类进行子类化。相同,能够通过插入非凡集成接口的实现来扩大Spring IoC容器。接下来的几节形容了这些集成接口。 1.8.1。自定义bean实现BeanBeanPostProcessor接口BeanPostProcessor接口定义了回调办法,您能够实现这些回调办法来批改默认的bean实例化的逻辑,依赖关系解析逻辑等。 如果您想在Spring容器实现实例化,配置和初始化bean之后实现一些自定义逻辑,则能够插入一个或多个自定义BeanPostProcessor。 您能够配置多个BeanPostProcessor实例,并且能够BeanPostProcessor通过实现Ordered 接口设置order属性来管制这些实例的运行程序。 @Componentpublic class MyBeanPostProcessor implements BeanPostProcessor, Ordered { @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } @Override public int getOrder() { return 0; }}BeanPostProcessor实例操作的是bean的实例。也就是说,Spring IoC容器实例化一个bean实例,而后应用BeanPostProcessor对这些实例进行解决加工。BeanPostProcessor实例是按容器划分作用域的。 仅在应用容器层次结构时,这才有意义。如果BeanPostProcessor在一个容器中定义一个,它将仅对该容器中的bean进行后处理。换句话说,一个容器中定义的bean不会被BeanPostProcessor另一个容器中的定义进行后处理,即便这两个容器是同一层次结构的一部分也是如此。BeanPostProcessor批改的是bean实例化之后的内容,如果要更改理论的bean定义(即bean definition)您须要应用 BeanFactoryPostProcessor接口.org.springframework.beans.factory.config.BeanPostProcessor接口恰好由两个回调办法组成。 当此类被注册为容器的post-processor时,对于容器创立的每个bean实例,post-processor都会在任何bean实例化之后并且在容器初始化办法(例如InitializingBean.afterPropertiesSet()或任何申明的init办法)被应用之前调用。 post-processor能够对bean实例执行任何操作,也能够齐全疏忽回调。 post-processor通常查看回调接口,或者能够用代理包装Bean。 一些Spring AOP根底构造类被实现为post-processor,以提供代理包装逻辑。 ApplicationContext自动检测实现BeanPostProcessor接口所有bean,留神是要注册成bean,仅仅实现接口是不能够的。请留神,通过应用@Bean工厂办法申明BeanPostProcessor时,工厂办法的返回类型应该是实现类自身或至多是org.springframework.beans.factory.config.BeanPostProcessor 接口,以分明地表明该bean的post-processor性质。 否则,ApplicationContext无奈在齐全创立之前按类型自动检测它。 因为BeanPostProcessor须要提前实例化以便利用于上下文中其余bean的初始化,因而这种晚期类型检测至关重要。 @Bean public BeanPostProcessor myBeanPostProcessor(){ return new MyBeanPostProcessor(); } 以编程形式注册BeanPostProcessor实例尽管举荐的BeanPostProcessor注册办法是通过ApplicationContext自动检测,然而您能够ConfigurableBeanFactory应用addBeanPostProcessor办法通过编程形式对它们进行注册。当您须要在注册之前评估条件逻辑(比方利用场景是xxx条件才注册,xxx条件不注册时),甚至须要跨层次结构的上下文复制Bean post-processor时,这将十分有用。然而请留神,以BeanPostProcessor编程形式增加的实例不恪守该Ordered接口。在这里,注册的程序决定了执行的程序。还要留神,以BeanPostProcessor编程形式注册的实例总是在通过自动检测注册的实例之前进行解决,而不思考任何明确的程序。BeanPostProcessor 实例和AOP主动代理实现BeanPostProcessor接口的类是非凡的,并且容器对它们的解决形式有所不同。BeanPostProcessor它们间接援用的所有实例和bean在启动时都会实例化,作为ApplicationContext的非凡启动阶段的一部分。接下来,BeanPostProcessor以排序形式注册所有实例,并将其利用于容器中的所有其余bean。然而因为AOP主动代理的实现是通过BeanPostProcessor接口,所以在AOP的BeanPostProcessor接口实例化之前的BeanPostProcessor实例或BeanPostProcessor实例间接援用的bean都没有资格进行主动代理。并且对于任何此类bean都没有任何解决切面的BeanPostProcessor指向他们。您应该看到一条参考性日志音讯:Bean someBean is not eligible for getting processed by all BeanPostProcessor interfaces (for example: not eligible for auto-proxying)。这条音讯的意思大略就是说这个bean没有失去所有BeanPostProcessor的解决上面剖析一下这条日志的逻辑:咱们不必AOP的BeanPostProcessor用AutowiredAnnotationBeanPostProcessor来看这个状况首先这条日志是在BeanPostProcessorChecker类中打印的,这个类自身就实现了BeanPostProcessor,Spring容器减少这个processor的代码如下: //获取所有的BeanPostProcessor类型的bean //第一个true示意包含非单例的bean //第二个false示意仅查找曾经实例化实现的bean,如果是factory-bean则不算入内 String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); //以后beanFactory内的所有post-processor数 + 1 + postBeanNames的数量 //这个数量在后续有个判断 //beanFactory.getBeanPostProcessorCount() 零碎内置processor //1 就是BeanPostProcessorChecker //postProcessorNames.length 就是能扫描到的processor //这个数量之和就是目前零碎能看到的所有processor //还有的就可能是解析完了某些bean又新增了processor那个不算在内 int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length; //add BeanPostProcessorChecker 进入beanPostProcessor链 beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));BeanPostProcessorChecker中判断并打印上边那条日志的办法如下: @Override public Object postProcessAfterInitialization(Object bean, String beanName) { //如果以后bean不是postProcessor的实例 //并且不是外部应用的bean //并且this.beanFactory.getBeanPostProcessorCount()小于方才相加的值 //三个都满足才会打印那行日志 if (!(bean instanceof BeanPostProcessor) && !isInfrastructureBean(beanName) && this.beanFactory.getBeanPostProcessorCount() < this.beanPostProcessorTargetCount) { if (logger.isInfoEnabled()) { logger.info("Bean '" + beanName + "' of type [" + bean.getClass().getName() + "] is not eligible for getting processed by all BeanPostProcessors " + "(for example: not eligible for auto-proxying)"); } } return bean; } //以后beanName不为空,并且对应的bean是容器外部应用的bean则返回true private boolean isInfrastructureBean(@Nullable String beanName) { if (beanName != null && this.beanFactory.containsBeanDefinition(beanName)) { BeanDefinition bd = this.beanFactory.getBeanDefinition(beanName); return (bd.getRole() == RootBeanDefinition.ROLE_INFRASTRUCTURE); } return false; } 在看Spring createBean时遍历postProcessor的代码 @Override public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }就是通过这么一个循环来执行后置办法applyBeanPostProcessorsAfterInitialization,前置办法也是这样的当初假如咱们有一个自定义的beanPostProcessor外面须要注入一个咱们自定义的beanA,那么在beanPostProcessor被实例化的时候必定会要求注入咱们自定义的beanA,那么当初就有多种状况了: 1.咱们用的set或者结构器注入那beanA会被实例化并注入 2.如果咱们用的@Autowired,当咱们自定义的beanPostProcessor实例化 在AutowiredAnnotationBeanPostProcessor实例化之前,那么beanA都无奈被注入值 如果在之后,则还是能够被注入值 然而这两种状况都会打印这行日志Bean 'beanA' of type [org.springframework.beanA] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)以下示例显示了如何在ApplicationContext中编写,注册和应用BeanPostProcessor实例。 ...

September 29, 2020 · 3 min · jiezi

关于spring:商品上架-下架-修改状态信息

剖析 jscontroller层 @ RequestMapping("updateStatus/{status}")public SysResult doInstockItem(@PathVariable Integer status,Long[]ids) { itemService.updateStatus(status,ids); return SysResult.success();}service层 //商品的上架 下架操作 就批改状态信息 void updateStatus(Integer status,Long[]ids);@Overridepublic void updateStatus(Integer status,Long[]ids) { Item item = new Item(); item.setStatus(status);//批改状态 UpdateWrapper<Item> updateWrapper=new UpdateWrapper<>(); List<Long>idList= Arrays.asList(ids);//数组转汇合 updateWrapper.in("id",idList);//参数须要的是汇合类型 itemMapper.update(item,updateWrapper);}

September 29, 2020 · 1 min · jiezi

关于spring:Spring-5-中文解析数据存储篇JDBC数据存储下

3.7 作为Java对象JDBC操作模型org.springframework.jdbc.object包蕴含一些类,这些类使你以更加面向对象的形式拜访数据库。例如,你能够运行查问并将后果作为蕴含业务对象的列表返回,该业务对象的关联列数据映射到业务对象的属性。你还能够运行存储过程并运行update,delete和insert语句。 许多Spring开发人员认为,上面形容的各种RDBMS操作类(StoredProcedure类除外)通常能够用间接的JdbcTemplate调用代替。通常,编写间接在JdbcTemplate上调用办法的DAO办法(与将查问封装为残缺的类绝对)更简略。然而,如果通过应用RDBMS操作类取得可测量的价值,则应持续应用这些类。3.7.1 了解SqlQuerySqlQuery是可重用的、线程平安的类,它封装了SQL查问。子类必须实现newRowMapper(..)办法以提供RowMapper实例,该实例能够为遍历查问执行期间创立的ResultSet所取得的每一行创立一个对象。很少间接应用SqlQuery类,因为MappingSqlQuery子类为将行映射到Java类提供了更为不便的实现。扩大SqlQuery的其余实现是MappingSqlQueryWithParameters和UpdatableSqlQuery。 3.7.2 应用MappingSqlQueryMappingSqlQuery是可重用的查问,其中具体的子类必须实现形象的mapRow(..)办法,以将提供的ResultSet的每一行转换为指定类型的对象。以下示例显示了一个自定义查问,该查问将t_actor关系中的数据映射到Actor类的实例: public class ActorMappingQuery extends MappingSqlQuery<Actor> { public ActorMappingQuery(DataSource ds) { super(ds, "select id, first_name, last_name from t_actor where id = ?"); declareParameter(new SqlParameter("id", Types.INTEGER)); compile(); } @Override protected Actor mapRow(ResultSet rs, int rowNumber) throws SQLException { Actor actor = new Actor(); actor.setId(rs.getLong("id")); actor.setFirstName(rs.getString("first_name")); actor.setLastName(rs.getString("last_name")); return actor; }}该类扩大了应用Actor类型参数化的MappingSqlQuery。此自定义查问的构造函数将DataSource作为惟一参数。在此构造函数中,能够应用DataSource和运行的SQL调用超类上的构造函数,以检索该查问的行。该SQL用于创立PreparedStatement,因而它能够蕴含在执行期间要传递的任何参数的占位符。你必须应用传入SqlParameter的declareParameter办法申明每个参数。SqlParameter具备名称,并且具备java.sql.Types中定义的JDBC类型。定义所有参数之后,能够调用compile()办法,以便能够筹备并稍后执行。此类在编译后是线程平安的,因而,只有在初始化DAO时创立这些实例,就能够将它们保留为实例变量并能够重用。上面的示例演示如何定义此类: private ActorMappingQuery actorMappingQuery;@Autowiredpublic void setDataSource(DataSource dataSource) { this.actorMappingQuery = new ActorMappingQuery(dataSource);}public Customer getCustomer(Long id) { return actorMappingQuery.findObject(id);}后面示例中的办法检索具备作为惟一参数传入的id的customer。因为只心愿返回一个对象,因而咱们以id为参数调用findObject便捷办法。相同,如果有一个查问返回一个对象列表并采纳其余参数,则将应用其中一种执行办法,该办法采纳以能够变参数模式传入的参数值数组。 ...

September 28, 2020 · 5 min · jiezi

关于spring:商品的增加操作全局异常处理

页面剖析url剖析页面JS剖析 业务实现SysResult VO对象的创立次要目标是为了与页面进行交互 package com.jt.vo;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import lombok.experimental.Accessors;//SysResult 次要的目标是为了与页面进行交互. ajax/json@Data@Accessors(chain = true)@NoArgsConstructor@AllArgsConstructorpublic class SysResult { private Integer status; //200胜利 201 失败 private String msg; //服务器提示信息 胜利 失败 private Object data; //服务器返回值数据. //能够利用static的静态方法 将数据动静返回 public static SysResult fail(){ return new SysResult(201, "业务执行失败", null); } /** * 1.只须要返回状态码信息 200 * 2.须要返状态及业务数据 200/data * 3.返回提示信息/data业务数据 * @return */ public static SysResult success(){ return new SysResult(200, "业务执行胜利!", null); } //String json = "{key:value}" public static SysResult success(Object data){ return new SysResult(200, "业务执行胜利!", data); } //只想返回提示信息 public static SysResult success(String msg,Object data){ return new SysResult(200, msg, data); }}编辑ItemController ...

September 28, 2020 · 1 min · jiezi

关于spring:第四阶段-day926-Spring-Boot

实现商品后盾治理============ 1.1 表格数据的展示形式1.1.1 编辑页面`</script>--> <table class="easyui-datagrid" style="width:500px;height:300px" data-options="url:'datagrid_data.json',method:'get',fitColumns:true,singleSelect:true,pagination:true"> <thead> <tr> <th data-options="field:'code',width:100">Code</th> <th data-options="field:'name',width:100">Name</th> <th data-options="field:'price',width:100,align:'right'">Price</th> </tr> </thead> </table>` 1.1.2 返回值类型的阐明属性信息: total/rows/属性元素 `{ "total":2000, "rows":[ {"code":"A","name":"果汁","price":"20"}, {"code":"B","name":"汉堡","price":"30"}, {"code":"C","name":"鸡柳","price":"40"}, {"code":"D","name":"可乐","price":"50"}, {"code":"E","name":"薯条","price":"10"}, {"code":"F","name":"麦旋风","price":"20"}, {"code":"G","name":"套餐","price":"100"} ]}` 1.2 JSON常识回顾1.2.1 JSON介绍JSON(JavaScript Object Notation) 是一种轻量级的数据交换格局。它使得人们很容易的进行浏览和编写。 1.2.2 Object对象类型 1.2.3 Array格局 1.2.4 嵌套格局例子: `{"id":"100","hobbys":["玩游戏","敲代码","看动漫"],"person":{"age":"19","sex":["男","女","其余"]}}` * 11.3 编辑EasyUITablle的VO对象`package com.jt.vo;import com.jt.pojo.Item;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import lombok.experimental.Accessors;import java.util.List;@Data@Accessors(chain = true)@NoArgsConstructor@AllArgsConstructorpublic class EasyUITable { private Long total; private List<Item> rows;}` 1.4 商品列表展示1.4.1 页面剖析业务阐明: 当用户点击列表按钮时.以跳转到item-list.jsp页面中.会解析其中的EasyUI表格数据.发动申请url:’/item/query’要求返回值必须满足特定的JSON构造,所以采纳EasyUITable办法进行数据返回. ...

September 28, 2020 · 4 min · jiezi

关于spring:Jaskson精讲第7篇类继承关系下的JSON序列化与反序列化JsonTypeInfo

Jackson是Spring Boot(SpringBoot)默认的JSON数据处理框架,然而其并不依赖于任何的Spring 库。有的小伙伴认为Jackson只能在Spring框架内应用,其实不是的,没有这种限度。它提供了很多的JSON数据处理办法、注解,也包含流式API、树模型、数据绑定,以及简单数据类型转换等性能。它尽管简略易用,但相对不是小玩具,更多的内容我会写成一个系列,5-10篇文章,请您持续关注我。 《序列化与反序列化外围用法-JSON框架Jackson精解第1篇》《非凡数据格式解决-JSON框架Jackson精解第2篇》《属性序列化自定义排序与字母表排序-JSON框架Jackson精解第3篇》《@JacksonInject与@JsonAlias注解-JSON框架Jackson精解第4篇》《@JsonCreator自定义反序列化函数-JSON框架Jackson精解第5篇》《Jaskson精讲第6篇-自定义JsonSerialize与Deserialize实现数据类型转换》本篇文章是系列文章的第7篇,次要是为大家介绍一下,在Java 类继承的状况下如何实现父类及子类的JSON序列化与反序列化。 一、继承关系对象构建首先构建一个ClsShape类示意形态。 public class ClsShape {}构建一个ClsCircle 类示意圆形。并增加了一系列的lombok注解,Data示意提供get、set、toString、hashCode等办法;EqualsAndHashCode注解在有继承关系的字类中应用;AllArgsConstructor和NoArgsConstructor别离提供全参和无参构造方法。 @Data@EqualsAndHashCode(callSuper = true)@AllArgsConstructor@NoArgsConstructorpublic class ClsCircle extends ClsShape { Integer radius; //弧度}构建一个长方形类ClsRectangle ,成员变量width宽度,height高度。 @Data@EqualsAndHashCode(callSuper = true)@AllArgsConstructor@NoArgsConstructorpublic class ClsRectangle extends ClsShape { private Integer width; private Integer height;}构建一个ClsView类,示意画面。画面中有很多的ClsShape形态,所以用一个List封装。 @Datapublic class ClsView { private List<ClsShape> shapes;}二、序列化与反序列化测试根底的形态类及画面类写完之后,上面的代码是用来实现:对象到Json字符串的序列化过程,和Json字符串反序列化为Java对象的过程代码。 @Testvoid testJSON2Object() throws IOException { ClsRectangle rectangle = new ClsRectangle(7,9); //构建正方形对象 ClsCircle circle = new ClsCircle(8); //构建长方形对象 List<ClsShape> shapes = new ArrayList<>(); //List<多种形态> shapes.add(circle); shapes.add(rectangle); ClsView view = new ClsView(); //将List放入画面View view.setShapes(shapes); ObjectMapper mapper = new ObjectMapper(); System.out.println("-- 序列化 --"); String jsonStr = mapper.writeValueAsString(view); System.out.println(jsonStr); System.out.println("-- 反序列化 --"); ClsView deserializeView = mapper.readValue(jsonStr, ClsView.class); System.out.println(deserializeView);}大家看最终在控制台的输入后果如下:序列化的过程是失常的,然而反序列化的时候报错了。 ...

September 28, 2020 · 1 min · jiezi

关于spring:Spring-5-中文解析数据存储篇JDBC数据存储中

3.5 JDBC批量操作如果将多个调用批处理到同一条筹备好的语句,则大多数JDBC驱动程序都会进步性能。通过将更新分组成批,能够限度到数据库的往返次数。 3.5.3 应用JdbcTemplate的根本批处理操作通过实现非凡接口的两个办法BatchPreparedStatementSetter并将该实现作为batchUpdate办法调用中的第二个参数传入,能够实现JdbcTemplate批处理。你能够应用getBatchSize办法提供以后批处理的大小。你能够应用setValues办法设置语句的参数值。此办法称为你在getBatchSize调用中指定的次数。以下示例依据列表中的条目更新t_actor表,并将整个列表用作批处理: public class JdbcActorDao implements ActorDao { private JdbcTemplate jdbcTemplate; public void setDataSource(DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); } public int[] batchUpdate(final List<Actor> actors) { return this.jdbcTemplate.batchUpdate( "update t_actor set first_name = ?, last_name = ? where id = ?", new BatchPreparedStatementSetter() { public void setValues(PreparedStatement ps, int i) throws SQLException { Actor actor = actors.get(i); ps.setString(1, actor.getFirstName()); ps.setString(2, actor.getLastName()); ps.setLong(3, actor.getId().longValue()); } public int getBatchSize() { return actors.size(); } }); } // ... additional methods}如果解决更新流或从文件读取,则可能具备首选的批处理大小,但最初一批可能没有该数量的条目(译者:意思是最初一批数据可能没有宰割数量大)。在这种状况下,能够应用InterruptibleBatchPreparedStatementSetter接口,该接口可在输出源耗尽后中断批处理(译者:意思是数据源数据耗费完)。isBatchExhausted办法使你能够收回批处理完结的信号。 ...

September 27, 2020 · 7 min · jiezi

关于spring:深入理解事务的传播行为

1.事务流传行为: 当咱们调用Service的某个事务办法时,如果该办法外部又调用其它Service的事务办法,则会呈现事务的嵌套。Spring定义了一套事务流传行为,请参考。这里咱们假设都用的REQUIRED这个类型:如果以后没有事务,就新建一个事务,如果曾经存在一个事务,则退出到的以后事务。2.事务流传行为只在同一个线程中存在,因为mybatis应用sqlSession连贯数据库应用的是ThreadLocal技术spring 的事务管理是线程平安的 3.事务的嵌套调用会用到sqlSessionHolder 参考链接:https://www.cnblogs.com/jians...Mybatis源码解析:https://www.cnblogs.com/chihi...spring中的事务流传行为例子:https://segmentfault.com/a/11...

September 27, 2020 · 1 min · jiezi

关于spring:吹爆阿里新发Spring源码高级笔记原来看懂源码如此简单

Spring的影响力想必无需与大家多说,如果你用spring,那么读读源码有助于对你最重要的工具的了解,好的框架源码也能够帮忙咱们了解什么是好代码。 刚加入工作那会,没想过来读源码,更没想过来改框架的源码;甚至感觉那些有事没事扯源码的人就是在装,只是为了进步他们的逼格而已,在工作中没什么太大的用;但当初我的想法扭转了,上面我就我本人的一些见解来与大家聊聊为什么要读Spring源码。 为什么要读Spring源码?说实话我读Spring源码一刚开始为了面试,起初为了解决工作中的问题,再起初就是集体爱好了。说的好听点是有匠人精力;说的婉转点是好奇(底层是怎么实现的);说的不自信点是对黑盒的货色我用的没底,怕用错;说的简略直白点是晋升自我价值,为了更高的薪资待遇(这里对真正的技术迷说声道歉)。正如后面所说的Spring的影响力大家引人注目,会读Spring源码无疑是一个硬核涨薪技能。要读Spring源码看书是个不错的抉择,自成体系,让咱们把握的知识点不至于太散。互联网雷锋(小编我)也是费尽心思为大家网罗到两份很nice的学习笔记供大家参考,须要的看我主页。 第一份文档Spring源码高级笔记(因为篇幅限度就只以截图的模式展现进去了) 第—局部Spring 概述第二局部核心思想第三局部手写实现loC和AOP第四局部Spring lOC利用第五局部Spring IOC源码深度分析第六局部Spring AOP利用第七局部Spring AOP源码深度分析目录一览: 笔记局部内容: 核心思想: 手写实现loC和AOP: Spring AOP利用: Spring AOP源码深度分析: 第二份文档Spring源码解析 本文档从外围实现和企业应用两个方面,由浅入深、由易到难地对Spring源码开展了零碎的解说,包含Spring 的设计理念和整体架构、容器的根本实现、默认标签的解析、自定义标签的解析、bean的加载、容器的性能扩大、AOP、数据库连贯JDBC、整合MyBatis、事务、SpringMVC、近程服务、Spring 音讯服务等内容。因为篇幅限度就只展现目录了~第一局部 外围实现 第1章 Spring整体架构和环境搭建第2章 容器的根本实现第3章 默认标签的解析第4章 自定义标签的解析第5章 bean的加载第6章 容器的性能扩大第7章 AOP第二局部 企业应用 第8章 数据库连贯JDBC第9章 整合MyBatis第10章 事务第11章 SpringMVC第12章 近程服务第13章 Spring音讯目录一览: 学习视频举荐: 须要大牛的课件,笔记看我主页~写在最初源码中咱们能够学到很多货色,学习他人高效的代码书写、学习他人对设计模式的纯熟应用、学习他人对整个架构的布局,等等。如果你还能找出其中的有余,那么祝贺你,你要飞升了!会应用诚然重要,但晓得为什么这么应用同样重要。从模拟中学习,从模拟中翻新。如果你在读Spring源码的过程中有什么纳闷跟不解,那么这两份文档跟这些学习视频肯定会对你有所帮忙,如果有须要的敌人只须要点赞文章,关注我之后看我主页简介

September 27, 2020 · 1 min · jiezi

关于spring:Spring学习笔记五JDBCTemplate事务管理

1 概述Spring为开发者提供了JDBCTemplate,能够简化很多数据库操作相干的代码,本文次要介绍JDBCTemplate的应用以及事务管理性能。 2 JDBC Template2.1 配置配置的话次要配置以下几项: 数据源:org.springframework.jdbc.datasource.DriverManager.DataSource数据库驱动:com.cj.mysql.jdbc.Driver,这里采纳的是MySQL 8,留神MySQL 5.7以下的驱动名字不同,另外若是其余数据库请对应批改数据库URL:jdbc:mysql://localhost:3306/test,MySQL默认的3306端口,数据库test数据库用户名数据库明码JDBC模板:org.springframework.jdbc.core.jdbcTemplate参考配置如下: <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test"/> <property name="username" value="test"/> <property name="password" value="test"/></bean><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/></bean><context:component-scan base-package="pers.dao"/>2.2 罕用办法int update(String sql,Object args[]):增/删/改操作,应用args设置其中的参数,返回更新的行数List<T> query(String sql,RowMapper<T> rowMapper,Object []args):查问操作,rowMapper将后果集映射到用户自定义的类中2.3 示例2.3.1 依赖首先导入依赖: <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.9.RELEASE</version></dependency><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.21</version></dependency>MySQL的版本请依据集体须要更改,或应用其余数据库的驱动。 2.3.2 配置文件残缺配置文件如下: <?xml version="1.0" encoding="utf-8" ?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test"/> <property name="username" value="test"/> <property name="password" value="test"/> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <context:component-scan base-package="pers.dao"/></beans>2.3.3 实体类public class MyUser { private Integer id; private String uname; private String usex;}2.3.4 数据拜访层增加@Repository以及@RequiredArgsConstructor: ...

September 27, 2020 · 3 min · jiezi

关于spring:Spring-5-中文解析数据存储篇JDBC数据存储上

下表概述的操作序列可能最好地显示了Spring框架JDBC形象提供的值。该表显示了Spring负责哪些操作以及哪些操作是你须要做的。 ActionSpringYou定义连贯参数 X关上连贯X 指定SQL语句。 X申明参数并提供参数值 X筹备并运行该语句。X 设置循环以遍历后果(如果有)。X 进行每次迭代的工作。 X解决任何异样。X 解决异样。X 敞开连贯,语句和后果集。X Spring框架负责解决使JDBC成为如此乏味的API的所有底层细节。 3.1 抉择一种用于JDBC数据库拜访的办法你能够抉择几种办法来形成JDBC数据库拜访的根底。除了JdbcTemplate的三种模式之外,新的SimpleJdbcInsert和SimpleJdbcCall办法还优化了数据库元数据,并且RDBMS Object款式采纳了一种相似于JDO Query设计的面向对象的办法。一旦开始应用这些办法之一,你依然能够混合搭配以蕴含来自其余办法的性能。所有办法都须要兼容JDBC 2.0的驱动程序,而某些高级性能则须要JDBC 3.0驱动程序。 JdbcTemplate是经典且最受欢迎的Spring JDBC办法。这种最低级别的办法和所有其余办法都在幕后应用JdbcTemplate。NamedParameterJdbcTemplate包装了一个JdbcTemplate来提供命名参数,而不是传统的JDBC ?占位符。当你有多个SQL语句参数时,此办法可提供更好的文档编制和易用性。SimpleJdbcInsert和SimpleJdbcCall优化数据库元数据以限度必要的配置量。这种办法简化了编码,因而你仅须要提供表或过程(存储过程)的名称,并提供与列名称匹配的参数映射。仅当数据库提供足够的元数据时,此办法才无效。如果数据库不提供此元数据,则必须提供参数的显式配置。RDBMS对象(包含MappingSqlQuery、SqlUpdate和StoredProcedure)要求你在数据拜访层初始化期间创立可重用且线程平安的对象。此办法以JDO查问为模型,其中定义查问字符串、申明参数并编译查问。实现后,能够应用各种参数值屡次调用execute(...)、update(...)和findObject(...)办法。3.2 包构造Spring框架的JDBC形象框架由四个不同的包组成: core: org.springframework.jdbc.core蕴含JdbcTemplate类及其各种回调接口,以及各种相干类。名为org.springframework.jdbc.core.simple的子包蕴含SimpleJdbcInsert和SimpleJdbcCall类。另一个名为org.springframework.jdbc.core.namedparam的子包蕴含NamedParameterJdbcTemplate类和相干的反对类。请参阅应用JDBC外围类管制根本JDBC解决和错误处理、JDBC批处理操作和应用SimpleJdbc类简化JDBC操作。datasource: org.springframework.jdbc.datasource蕴含一个实用程序类,用于轻松拜访DataSource和各种简略DataSource实现,可用于在Java EE容器之外测试和运行未修改的JDBC代码。名为org.springfamework.jdbc.datasource.embedded的子包提供了对应用Java数据库引擎(例如HSQL、H2和Derby)创立嵌入式数据库的反对。请参阅管制数据库连贯和嵌入式数据库反对。object: org.springframework.jdbc.object蕴含一些类,这些类将RDBMS查问、更新和存储过程示意为线程平安的可重用对象。请参阅将JDBC操作建模为Java对象。只管查问返回的对象天然会与数据库断开连接,然而JDO对此办法进行了建模。较高级别的JDBC形象依赖于org.springframework.jdbc.core包中的较低级别的形象。support: org.springframework.jdbc.support包提供了SQLException转换性能和一些实用程序类。JDBC解决期间引发的异样将转换为org.springframework.dao包中定义的异样。这意味着应用Spring JDBC形象层的代码不须要实现JDBC或RDBMS特定的错误处理。所有转换的异样均为uncheck异样,这使你能够抉择捕捉可从中复原的异样,同时将其余异样传递到调用方。请参见应用SQLExceptionTranslator。3.3 应用JDBC外围类管制JDBC解决和错误处理本节介绍如何应用JDBC外围类管制JDBC解决,包含错误处理。它包含以下主题: 应用JdbcTemplate应用NamedParameterJdbcTemplate应用SQLExceptionTranslator执行语句执行查问更新数据库获取主动生成主键3.3.1 应用JdbcTemplateJdbcTemplate是JDBC的core包中的外围类。它解决资源的创立和开释,这有助于你防止常见的谬误,例如遗记敞开连贯。它执行外围JDBC工作流程的根本工作(例如,语句创立和执行),而使利用程序代码提供SQL并提取后果。JdbcTemplate类: 运行SQL查问更新语句和存储过程调用对ResultSet实例执行迭代并提取返回的参数值。捕捉JDBC异样并将其转换为org.springframework.dao包中定义的通用、信息量更大的异样层次结构。 (请参见统一的异样层次结构)当将JdbcTemplate用于代码时,只需实现回调接口,即可为它们提供明确定义的约定。给定JdbcTemplate类提供的Connection、PreparedStatementCreator回调接口将创立一条筹备好的语句,提供SQL和任何必要的参数。对于CallableStatementCreator接口(创立可调用语句)也是如此。 RowCallbackHandler接口从ResultSet的每一行提取值。 你能够通过间接实例化DataSource援用在DAO实现中应用JdbcTemplate,也能够在Spring IoC容器中对其进行配置,并将其作为Bean援用提供给DAO。 应该始终在Spring IoC容器中将DataSource配置为Bean。在第一种状况下,bean被间接提供给服务。在第二种状况下,将其提供给筹备好的模板。此类收回的所有SQL都在DEBUG级别下记录,该类别对应于模板实例的全限定类名称(通常为JdbcTemplate,但如果应用JdbcTemplate类的自定义子类,则可能有所不同)。 以下各节提供了JdbcTemplate用法的一些示例。这些示例不是JdbcTemplate裸露的所有性能的详尽列表。请参考附带的javadoc。 查问(SELECT) 以下查问获取关联中的行数: int rowCount = this.jdbcTemplate.queryForObject("select count(*) from t_actor", Integer.class);以下查问应用绑定变量: int countOfActorsNamedJoe = this.jdbcTemplate.queryForObject( "select count(*) from t_actor where first_name = ?", Integer.class, "Joe");以下查问查找字符串: String lastName = this.jdbcTemplate.queryForObject( "select last_name from t_actor where id = ?", String.class, 1212L);以下查问查找并填充单个畛域对象: ...

September 26, 2020 · 7 min · jiezi

关于spring:Spring-boot-启动提示数据源错误

在启动 Spring Boot 的我的项目的时候提醒数据源未配置的谬误。 09:52:08.333 [main] DEBUG o.s.b.d.LoggingFailureAnalysisReporter - Application failed to start due to an exceptionorg.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Failed to determine a suitable driver class at org.springframework.boot.autoconfigure.jdbc.DataSourceProperties.determineDriverClassName(DataSourceProperties.java:233) at org.springframework.boot.autoconfigure.jdbc.DataSourceProperties.initializeDataSourceBuilder(DataSourceProperties.java:174) Spring 会提醒你残缺的导致启动谬误的信息是: ***************************APPLICATION FAILED TO START***************************Description:Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.Reason: Failed to determine a suitable driver classAction:Consider the following: If you want an embedded database (H2, HSQL or Derby), please put it on the classpath. If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).Process finished with exit code 1 谬误剖析从下面的启动信息来看,曾经说得十分分明了,就是因为你配置了 Spring 的数据组件,然而你没有配置相应的数据源。 ...

September 26, 2020 · 1 min · jiezi

关于spring:没有公网IP使用Ngrok将局域网服务映射到公网

这篇文章将为大家介绍ngrok,如何装置,配置以及在什么场景下须要应用ngrok。在没有应用过Ngrok之前,您可能会遇到过这样一些状况 你须要向客户演示你们正在研发的我的项目,所以你要求开发人员帮忙你,在你的资源无限的笔记本电脑上部署一套用于给客户演示的环境。当下一次另一个共事须要去为客户演示的时候,同样的事件又要重做一遍。您如果作为一个挪动利用的后端服务开发者,与挪动利用的前端开发者组成一个近程团队。你须要帮忙前端开发者,在他的网络内部署一套用于测试的环境。因为前端开发者不具备后端技术栈,所以你们之间对于后端测试环境的沟通老本极高。所有的这所有问题,只有您有一个固定的公网ip就能够解决了,将后端服务裸露在公网ip上,在互联网的任何地位都能够被拜访到。然而咱们都晓得固定的公网ip价格是很贵的,依据带宽的不同,每年的费用从万元到几十万元不等。如果只是为了演示、测试、及研发环境等网络共享的问题,齐全没有必要申请固定的公网ip。 那么有没有什么代替的计划呢?当然就是咱们这篇文章的配角:Ngrok。 一、什么是Ngrok?Ngrok是Alan Shreeve开发的应用程序,使开发人员能够将其本地开发服务公开到Internet上。它会创立一条通往本地开发服务器的网络,并生成两个随机的子域名-一个http一个是https。应用这些生成的域名地址,只有本地服务放弃失常运行,您就能够通过Internet从任何中央拜访本地开发的应用程序。 二、如何应用ngrok?应用ngrok非常简单。 设置与装置配置ngrok启动网络服务1.设置和装置要开始应用ngrok,咱们必须在提供ngrok服务的网站注册一个帐户ngrok。注册后到仪表板页面。依据您的操作系统下载正确的软件包。 对于Windows:下载zip并解压缩可执行文件并运行它。要让ngrok命令在零碎内任何地位拜访,能够应用上面办法 将可执行文件ngrok.exe移至C:\Windows\system32\ngrok.exe增加环境变量(在Windows徽标旁边的搜寻栏中搜寻“为您的帐户编辑环境变量” =>双击“用户变量”下的“您的用户名”的门路=>单击“新建” =>增加门路C:\Windows\system32\ngrok.exe =>单击“确定”。对于Mac / Linux:-在终端上运行以下命令。 unzip /path/to/ngrok.zip将ngrok文件挪动到/usr/local/bin目录或依据你应用的shell将门路增加到到.bashrc或.zshrc。 2.配置并验证ngrok下一步是应用您的ngrok帐户验证您在零碎上装置的ngrok客户端的可用性。 在终端/提示符下运行以下命令: ngrok authtoken YOUR_AUTH_TOKENYOUR_AUTH_TOKEN是显示在仪表板上的令牌。这会将您帐户的auth_token保留到本地计算机中的.yml文件中。 3.启动网络服务输出以下命令: ./ngrok http 3000这个3000是您的本地服务器运行的端口号,也就是你的本地服务的启动端口,依据你本人的状况应用命令启动。 通过运行此命令,您的终端提醒应如下所示。上图显示了可在其中拜访应用程序的随机生成的子域URL,能够在公网上进行拜访。此外,您还能够通过浏览器拜访4040本地端口服务的仪表盘,在这里您能够查看通过生成的子域收回的所有申请。 祝贺!!您已胜利启动了ngrok应用程序,提供公网服务拜访。欢送关注我的博客,外面有很多精品合集本文转载注明出处(必须带连贯,不能只转文字):字母哥博客 - zimug.com 感觉对您有帮忙的话,帮我点赞、分享!您的反对是我不竭的创作能源! 。另外,笔者最近一段时间输入了如下的精品内容,期待您的关注。 《手摸手教你学Spring Boot2.0》《Spring Security-JWT-OAuth2一本通》《实战前后端拆散RBAC权限管理系统》《实战SpringCloud微服务从青铜到王者》《VUE深入浅出系列》

September 26, 2020 · 1 min · jiezi

关于spring:apline无法向gitlab上传git-lfs问题

1 背景在k8s中基于alpine做底层零碎的容器进行git lfs push操作时,发现报错无奈上传胜利 Fatal error: Server error: http://git.ops.xxxxx.com/xxxx/yyyy.git/gitlab-lfs/objects/b6f9dd313cde39ae1b87e63b9b457029bcea6e9520b5db5de20d3284e4c0259e/3 error: failed to push some refs to 'http://git.ops.xxxx.com/xxxx/yyyy.git'而git clone、commit等操作均失常,并且git lfs push的操作在另一个机器A上能失常执行。 2 摸索思路2.1 从报错动手先依据报错信息搜寻,根本答复是此报错是git server(gitlab)侧产生谬误,不过能够应用如下命令来打印trace跟踪信息(via: https://github.com/git-lfs/gi... GIT_TRACE=1 GIT_TRANSFER_TRACE=1 GIT_CURL_VERBOSE=1 git push origin xxx/xxx的确打印了更多信息,包含与Server的申请过程,如下: 07:18:13.442791 trace git-lfs: HTTP: POST http://xxxx:xxxx@git.ops.yunnex.com/suncard/packages.git/info/lfs/objects/batch> POST /suncard/packages.git/info/lfs/objects/batch HTTP/1.1> Host: git.ops.yunnex.com> Accept: application/vnd.git-lfs+json; charset=utf-8> Content-Length: 158> Content-Type: application/vnd.git-lfs+json; charset=utf-8> User-Agent: git-lfs/2.5.1 (GitHub; linux amd64; go 1.11.4; git 7c940069fa)> {"operation":"upload","objects":[{"oid":"b6f9dd313cde39ae1b87e63b9b457029bcea6e9520b5db5de20d3284e4c0259e","size":3}],"ref":{"name":"refs/heads/test-branch"}}07:18:13.618655 trace git-lfs: HTTP: 200< HTTP/1.1 200 OK< Transfer-Encoding: chunked< Cache-Control: max-age=0, private, must-revalidate< Connection: keep-alive< Content-Type: application/json; charset=utf-8< Date: Thu, 24 Sep 2020 07:18:13 GMT< Etag: W/"0fb39c6aeeda2850fdcf244083961713"< Server: nginx< Strict-Transport-Security: max-age=31536000< X-Content-Type-Options: nosniff< X-Frame-Options: DENY< X-Request-Id: 570154fd-b15f-4e8a-a735-b034e98dfbfd< X-Runtime: 0.165423< X-Ua-Compatible: IE=edge< X-Xss-Protection: 1; mode=block< 07:18:13.619071 trace git-lfs: HTTP: {"objects":[{"oid":"b6f9dd313cde39ae1b87e63b9b457029bcea6e9520b5db5de20d3284e4c0259e","size":3,"actions":{"upload":{"href":"http://git.ops.yunnex.com/suncard/packages.git/gitlab-lfs/objects/b6f9dd313cde39ae1b87e63b9b457029bcea6e9520b5db5de20d3284e4c0259e/3","header":{"Authorization":"Basic cHJvZHVjdGlvbjpVc2VfMTk5MA=="}}}}]}{"objects":[{"oid":"b6f9dd313cde39ae1b87e63b9b457029bcea6e9520b5db5de20d3284e4c0259e","size":3,"actions":{"upload":{"href":"http://git.ops.yunnex.com/suncard/packages.git/gitlab-lfs/objects/b6f9dd313cde39ae1b87e63b9b457029bcea6e9520b5db5de20d3284e4c0259e/3","header":{"Authorization":"Basic cHJvZHVjdGlvbjpVc2VfMTk5MA=="}}}}]}07:18:13.619307 trace git-lfs: tq: starting transfer adapter "basic"07:18:13.619345 trace git-lfs: xfer: adapter "basic" Begin() with 8 workers07:18:13.619383 trace git-lfs: xfer: adapter "basic" started07:18:13.619413 trace git-lfs: xfer: adapter "basic" worker 1 starting07:18:13.619537 trace git-lfs: xfer: adapter "basic" worker 1 waiting for Auth07:18:13.619549 trace git-lfs: xfer: adapter "basic" worker 5 starting07:18:13.619585 trace git-lfs: xfer: adapter "basic" worker 5 waiting for Auth07:18:13.619642 trace git-lfs: xfer: adapter "basic" worker 0 starting07:18:13.619673 trace git-lfs: xfer: adapter "basic" worker 6 starting07:18:13.619681 trace git-lfs: xfer: adapter "basic" worker 0 processing job for "b6f9dd313cde39ae1b87e63b9b457029bcea6e9520b5db5de20d3284e4c0259e"07:18:13.619702 trace git-lfs: xfer: adapter "basic" worker 7 starting07:18:13.619722 trace git-lfs: xfer: adapter "basic" worker 7 waiting for Auth07:18:13.619732 trace git-lfs: xfer: adapter "basic" worker 2 starting07:18:13.619775 trace git-lfs: xfer: adapter "basic" worker 2 waiting for Auth07:18:13.619723 trace git-lfs: xfer: adapter "basic" worker 4 starting07:18:13.619775 trace git-lfs: xfer: adapter "basic" worker 3 starting07:18:13.619805 trace git-lfs: xfer: adapter "basic" worker 3 waiting for Auth07:18:13.619788 trace git-lfs: xfer: adapter "basic" worker 4 waiting for Auth07:18:13.619697 trace git-lfs: xfer: adapter "basic" worker 6 waiting for Auth07:18:13.621028 trace git-lfs: HTTP: PUT http://git.ops.yunnex.com/suncard/packages.git/gitlab-lfs/objects/b6f9dd313cde39ae1b87e63b9b457029bcea6e9520b5db5de20d3284e4c0259e/3> PUT /suncard/packages.git/gitlab-lfs/objects/b6f9dd313cde39ae1b87e63b9b457029bcea6e9520b5db5de20d3284e4c0259e/3 HTTP/1.1> Host: git.ops.yunnex.com> Authorization: Basic * * * * *> Content-Length: 3> Content-Type: text/plain; charset=utf-8> User-Agent: git-lfs/2.5.1 (GitHub; linux amd64; go 1.11.4; git 7c940069fa)> 07:18:13.621492 trace git-lfs: xfer: adapter "basic" worker 7 auth signal receiveddd07:18:13.621527 trace git-lfs: xfer: adapter "basic" worker 5 auth signal received07:18:13.621536 trace git-lfs: xfer: adapter "basic" worker 4 auth signal received07:18:13.621563 trace git-lfs: xfer: adapter "basic" worker 2 auth signal received07:18:13.621571 trace git-lfs: xfer: adapter "basic" worker 3 auth signal received07:18:13.621579 trace git-lfs: xfer: adapter "basic" worker 6 auth signal received07:18:13.621522 trace git-lfs: xfer: adapter "basic" worker 1 auth signal received07:18:13.786463 trace git-lfs: HTTP: 500< HTTP/1.1 500 Internal Server Error< Content-Length: 2911< Cache-Control: no-cache, no-store, max-age=0, must-revalidate< Connection: keep-alive< Content-Type: text/html; charset=utf-8< Date: Thu, 24 Sep 2020 07:18:13 GMT< Expires: Fri, 01 Jan 1990 00:00:00 GMT< Pragma: no-cache< Server: nginx< X-Request-Id: 0574e8c0-8ee8-4667-8141-1982d67c0bdc< X-Runtime: 0.162882< 07:18:13.786829 trace git-lfs: xfer: adapter "basic" worker 0 finished job for "b6f9dd313cde39ae1b87e63b9b457029bcea6e9520b5db5de20d3284e4c0259e"07:18:13.786927 trace git-lfs: tq: retrying object b6f9dd313cde39ae1b87e63b9b457029bcea6e9520b5db5de20d3284e4c0259e: Fatal error: Server error: http://git.ops.yunnex.com/suncard/packages.git/gitlab-lfs/objects/b6f9dd313cde39ae1b87e63b9b457029bcea6e9520b5db5de20d3284e4c0259e/307:18:13.787030 trace git-lfs: tq: enqueue retry #1 for "b6f9dd313cde39ae1b87e63b9b457029bcea6e9520b5db5de20d3284e4c0259e" (size: 3)07:18:13.787091 trace git-lfs: tq: sending batch of size 107:18:13.787212 trace git-lfs: api: batch 1 files07:18:13.787330 trace git-lfs: HTTP: POST http://xxxxx:xxxxx@git.ops.yunnex.com/suncard/packages.git/info/lfs/objects/batch...一直重试反复雷同日志其中要害申请如下 ...

September 25, 2020 · 7 min · jiezi

关于spring:想要搭建个论坛Guide哥调研了100来个-Java-开源论坛系统发现这-5-个最好用

大家好!我是 Guide 哥,Java 后端开发。一个会一点前端,喜爱烹饪的自在少年。 最近有点小忙。然而,因为前几天许可了一位读者本人会举荐一些开源的论坛零碎,所以,昨晚就简略地熬了个夜,比照了很多个开源论坛零碎之后,总结成了这篇文章。 这篇文章我一共举荐了 5 个论坛类开源我的项目,除了有 1 个是基于 PHP 开发之外,其余都是基于 Java ,并且大部分都是基于 Spring Boot 这个支流框架来做的。 欢送小伙伴们在评论区补充啊!( ´・・` )比心 1. NiterForumGithub 地址:https://github.com/yourkevin/NiterForum官网地址:https://niter.cn/forumStar : 0.5k简介:尼特社区-NiterForum-一个论坛程序,简直具备一个论坛/社区所应该有的全副性能-后端 Springboot/MyBatis/Maven/MySQL-前端 Thymeleaf/Layui-可供初学者,学习、交换应用。技术栈: 后端 Springboot + MyBatis + Maven + MySQL 前端 Thymeleaf + Layui举荐等级 :⭐⭐⭐⭐⭐评估:能够说 NiterForum 提供了一个论坛所能提供的所有性能,性能个性笼罩的十分全面。但这并不是这次举荐他的次要起因。作为本次论坛我的项目中第一个举荐的我的项目,NiterForum 的 NB 之处就是:他提供 NiterApp,完满适配了 NiterForum,反对 app 端扫码登录! 2. SymphonyGithub 地址:https://github.com/88250/symphony官网地址:https://ld246.com/Star : 0.7k简介:???? 一款用 Java 实现的现代化社区(论坛/问答/BBS/社交网络/博客)零碎平台。技术栈: Latke (作者自研的以 JSON 为主的 Java Web 框架)+jsoup + Jodd举荐等级 :⭐⭐⭐⭐评估:讲真,Symphony 是笔者目前见过的论坛我的项目中性能最齐全的一款(没有之一),满足多维需要:面向内容、面向常识问答、面向用户分享、交友、游戏等。而且 Symphony 格调时尚,充斥翻新、好玩的个性。交互体验一级棒。这个我的项目的毛病也很显著,那就是我的项目应用的技术栈不是支流,比拟小众(_不过,作者自研 Java Web 框架的精力还是十分值得赞叹的!_)。 ...

September 23, 2020 · 1 min · jiezi

关于spring:万字长文详解Spring-Security基于表单登录的认证模式

本文思维导图 图1 思维导图 原理探讨当咱们在我的项目中引入 Spring Security 的相干依赖后,默认的就是表单登录模式;俗话说:“听人劝,吃饱饭”,既然 Spring Security 曾经给咱们安顿的明明白白了,咱们就从表单登录开始吧。 在开始之前,咱们能够站在 Spring Security 的角度上思考:如果我本人来实现表单登录的性能,那么我须要做哪些工作呢? 就我集体而言,我可能会思考以下几点: 配置用户信息,存储如账号、明码等;明码不能以明文传输,须要加密性能执行校验认证胜利或者失败的解决计划能够简略的制作成如下流程图: 图1-1 表单登录简略流程图 上方属于咱们本人构想的实现计划,属于"低配版"模式,上面咱们来看看 Spring Security 是怎么做的。Spring Security的思路和咱们大同小异,长处在于其提供了很好的封装,进步了框架自身的可扩展性。 Spring Security 的实现步骤如下: UsernamePasswordAuthenticationFilter拦截器拦挡前端传递的表单登录申请,将登录信息(username、password)封装成 UsernamePasswordAuthenticationToken,传递给 AuthenticationManager认证管理器AuthenticationManager认证管理器依据Token的类型遍历获取对应的Provider,也即是 DaoAuthenticationProvider,执行认证流程DaoAuthenticationProvider 依附 PasswordEncoder 和 UserDetailsService对登录申请进行验证验证通过,由AuthenticationSuccessHandler 认证胜利处理器进行解决验证失败,由AuthenticationFailureHandler 认证失败处理器进行解决制作成流程图如示: 图1-2 Spring Security表单登录认证流程图 这时你可能会一脸懵逼:这咋和刚刚咱们本人构想的齐全不一样呀~ 又是Manager又是Provider的;莫慌,且听我缓缓道来。 下面呈现了很多新的概念,咱们目前不须要非常粗疏的理解它们是怎么发挥作用的,只须要大略晓得它们有什么用的即可;具体的介绍会在下篇《认证(二):表单登录认证流程源码解析》娓娓道来。 UsernamePasswordAuthenticationFilter 表单登录拦截器,用以捕捉前端传递的登录信息(username、password),并将登录信息封装成某些Token。AuthenticationManager 认证管理器,可简略的了解为调配工作的领导。DaoAuthenticationProvider DAO认证处理器,相当于被安顿干活的童鞋;从名字DAO也能够简略的揣测出:它与数据库中的用户信息密不可分。PasswordEncoder 明码加密器,明码不能明文传输,须要加密。UserDetailsService 用户信息Service层,这个也很好了解,前端传递的登录信息必定是有对应的数据库实体存储。AuthenticationSuccessHandler 认证胜利处理器 AuthenticationFailureHandler 认证失败处理器。通过上述的原理探讨,咱们大体上能弄懂了整个表单登录有哪几个模块须要解决;可简略的总结为3个模块: 登录前置解决:用户信息的封装、明码加密器的设置登录中解决:登录的校验登录后置解决:登录失败、登录胜利的解决计划小试牛刀俗话说:“光说不练假把式”,那么就让咱们来实战一番吧。 登录前置解决作为一个Java Web我的项目,第一步当然是引入相干依赖;间接引入Spring Boot封装好的starter即可。 Step-1 配置用户信息Spring Security 提供了UserDetails接口,用于获取用户的根本信息(账号密码、权限汇合、是否锁定等等),咱们只须要依据本身的业务场景,实现该接口即可。 Spring Security提供的UserDetails.class接口 自定义业务相干的用户信息类,业务定义的UserInfo.class必须带有username和password相干的信息,用于做用户验证;我的项目依据本身需要来判断是否须要应用上面的几个boolean办法,如果无相干需要则间接返回true即可。 @Setterpublic class UserInfo implements UserDetails {    private String username;    private String password;    /**     * UserDetails的接口     * 用户权限集,默认须要增加ROLE_作为前缀     */    @Override    public Collection<? extends GrantedAuthority> getAuthorities() {        List<SimpleGrantedAuthority> simpleGrantedAuthorities = new ArrayList<>(1);        simpleGrantedAuthorities.add(new SimpleGrantedAuthority("ROLE_USER"));        return simpleGrantedAuthorities;    }    /**     * 获取用户明码     */    @Override    public String getPassword() {        return this.password;    }    /**     * 获取用户名     */    @Override    public String getUsername() {        return this.username;    }    /**     * 账户是否未过期  --true则为未过期     */    @Override    public boolean isAccountNonExpired() {        return true;    }    /**     * 账户是否未被锁定     */    @Override    public boolean isAccountNonLocked() {        return true;    }    /**     * 账户凭证是否未过期     */    @Override    public boolean isCredentialsNonExpired() {        return true;    }    /**     * 账户是否可用     */    @Override    public boolean isEnabled() {        return true;    }} 在定义完用户实体UserInfo后,咱们同时也须要提供对应的Service层的API办法,用以进行一些根本的操作,诸如:新增用户、删除用户等。 Spring Security 也提供了对应的Service层接口,UserDetailsService,接口只有一个办法:UserDetails loadUserByUsername(String username);依据用户名加载用户信息. UserDetailsService.class public interface UserDetailsService {    UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;} 因而咱们能够自定义业务相干的UserInfoServiceImpl类,实现Spring Security提供的 UserDetailsService接口 UserInfoServiceImpl.class /** * 用户信息service模块 * * UserDetailsService接口为SpringSecurity内置接口,外部有办法: * UserDetails loadUserByUsername(String username):如名所得 依据用户名加载用户 * 该办法次要是在:DaoAuthenticationProvider中被调用,获取用户的信息 * * @author 小奇 */@Slf4j@Servicepublic class UserInfoServiceImpl implements UserDetailsService, UserInfoService {    private final UserInfoDAO userInfoDAO;    @Autowired    public UserInfoServiceImpl(UserInfoDAO userInfoDAO) {        this.userInfoDAO = userInfoDAO;    }    @Override    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {        Optional<UserInfo> userInfoOpt = Optional.ofNullable(userInfoDAO.loadUserByUsername(username));        UserInfo user = userInfoOpt.orElseThrow(() -> new UsernameNotFoundException("can't not load user by username"));        log.info("依据用户名:{}查问用户胜利", user.getUsername());        return user;    }} Step-2 配置明码加密器家喻户晓,明码是不能以明文的形式存储的,贴心的Spring Security天然不会遗记提供加密的性能。PasswordEncoder接口,次要提供2个办法;String encode(CharSequence rawPassword)办法用于加密,由咱们在注册用户的时候调用;boolean matches(CharSequence rawPassword, String encodedPassword) 办法用于匹配,登录验证时由Spring Security框架调用。 PasswordEncoder.class ...

September 23, 2020 · 1 min · jiezi

关于spring:JsonCreator自定义反序列化函数JSON框架Jackson精解第5篇

Jackson是Spring Boot(SpringBoot)默认的JSON数据处理框架,然而其并不依赖于任何的Spring 库。有的小伙伴认为Jackson只能在Spring框架内应用,其实不是的,没有这种限度。它提供了很多的JSON数据处理办法、注解,也包含流式API、树模型、数据绑定,以及简单数据类型转换等性能。它尽管简略易用,但相对不是小玩具,更多的内容我会写成一个系列,5-10篇文章,请您持续关注我。 《序列化与反序列化外围用法-JSON框架Jackson精解第1篇》《非凡数据格式解决-JSON框架Jackson精解第2篇》《属性序列化自定义排序与字母表排序-JSON框架Jackson精解第3篇》《@JacksonInject与@JsonAlias注解-JSON框架Jackson精解第4篇》本节持续为大家介绍在JSON反序列化过程中,如何应用@JsonCreator注解和@ConstructorProperties注解自定义反序列化函数。 一、Jackson反序列化过程做了什么?对于Jackson的JSON数据格式,反序列化过程就是将JSON字符串反序列化为java 对象。 ObjectMapper mapper = new ObjectMapper();//将JSON字符串反序列化为java对象String jsonInString = "{\"name\":\"乔丹\",\"age\":45,\"hobbies\":[\"高尔夫球\",\"棒球\"]}";PlayerStar3 jordan = mapper.readValue(jsonInString, PlayerStar3.class);System.out.println(jordan);默认状况下,Jackson在反序列化过程中调用了哪些函数,给大家介绍一下 首先调用反序列化的指标类PlayerStar3的无参构造函数,结构一个java对象而后调用该类的成员变量的set办法,为该对象的每一个成员变量赋值。所以默认状况下,一个Java类应用Jackson做反序列化,必须有public无参构造函数(java中不写也默认有),必须有成员变量的set办法。 二、@JsonCreator注解默认状况下,Jackson的反序列化过程是下面形容的那样,应用无参构造函数及set办法。除此之外,咱们还能够应用@JsonCreator注解自定义反序列化的过程,在咱们自定义的反序列化函数外面,咱们有更强的灵活性,能够实现更多的非规定动作。一共有两种自定义反序列化渠道: @JsonCreator注解加在构造方法上@JsonCreator注解加在工厂静态方法上应用了@JsonCreator注解之后,将应用该注解标注的办法进行反序列化对象的结构,默认的应用无参构造函数及set办法进行反序列化的过程生效。 2.1.@JsonCreator注解加在构造方法上该PlayerStar3对应的JSON字符串是第一大节中的jsonInString。下文的构造函数,你心愿将哪些属性值赋值给java 对象的成员变量,你就应用@JsonProperty("salary")去定义它。 public class PlayerStar3 { private String name; private Integer age; private String[] hobbies; //业余爱好,数组 private List<String> friends; // 敌人 private Map<String, BigDecimal> salary; //年收入 Map //这段是咱们的外围代码,应用JsonCreator注解阐明该办法是反序列化构造方法。 @JsonCreator public PlayerStar3(@JsonProperty("name") String name, @JsonProperty("age") Integer age, @JsonProperty("hobbies") String[] hobbies, @JsonProperty("friends") List<String> friends, @JsonProperty("salary") Map<String, BigDecimal> salary) { this.name = name; this.age = age; this.hobbies = hobbies; this.friends = friends; this.salary = salary; } //这里省略一个toString()办法}咱们应用第一大节中的反序列化代码,将jsonInString反序列化结构PlayerStar3对象,控制台输入后果如下(对象的toString()办法输入): ...

September 23, 2020 · 1 min · jiezi

关于spring:定时任务与feign超时的纠葛该咋优化

1 背景业务定时器利用中午常常会触发熔断异样的告警邮件 依据邮件提醒的类找到演绎以下表格 编号报错办法接口所属利用所属定时工作类AVipTradeReportFeignService#getShopTradeReportByDatepinka-mod-statsShopOrderSturctureTaskBVipMemberStatsFeignService#statMemberRecordpinka-mod-statsMemberStatTaskCVipPartnerWalletFeignService.handlePartnerWithdrawpinka-mod-customerPartnerWithdrawCheckTaskDVipWeixinBabyActivityFeignService.getBabyActivityNoticePagepinka-mod-weixinVipWeixinBabyNoticeTask以上A~D都是在一个分布式定时器事件处理利用(pinka-mod-scheduler)中对外的feign微服务调用产生的,相当于4类工作,每类都会调1次或屡次内部feign微服务接口,而其中的A~D接口产生了问题 其中A和B都是如下模式的异样 com.netflix.hystrix.exception.HystrixTimeoutExceptionat com.netflix.hystrix.AbstractCommand$HystrixObservableTimeoutOperator$1$1.run(AbstractCommand.java:1154)at com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable$1.call(HystrixContextRunnable.java:45)at com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable$1.call(HystrixContextRunnable.java:41)...而C和D都是如下模式的异样 feign.RetryableException: 10.13.32.111:56000 failed to respond executing POST http://pinka-mod-customer/vip/partner/wallet/handlePartnerWithdrawat feign.FeignException.errorExecuting(FeignException.java:67)at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:104)at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:76)at feign.hystrix.HystrixInvocationHandler$1.run(HystrixInvocationHandler.java:114)...Caused by: org.apache.http.NoHttpResponseException: 10.13.32.111:56000 failed to respondat org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:141)at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)...2 追究2.1 HystrixTimeoutException超时异样A与B的异样简直每天都产生,且提醒很显著,是Hystrix中设置了超时工夫(目前为10s),并且执行超时导致的。为何会超时?去接口实现发现是有for循环场景的耗时逻辑通过Kibana日志零碎查历史执行耗时,也能够发现都根本>13s,所以这类异样根本确因 2.1.1 解决与思考这其实是一个很典型场景,定时器工作执行并且解决逻辑是在另外一个微服务中,而解决逻辑属于简单耗时,怎么办? A. 减少超时工夫,这是个粗犷的思路,因为设长了可能导致更大的问题,因为超时原本就是为了fastfail,设20s那之后可能还会遇到要30s甚至更久的场景。所以这个计划不能用在所有调用的公共默认超时工夫上; 然而能够思考用在某些接口上,比方VipTradeReportFeignService#getShopTradeReportByDate接口评估失常耗时就是要15s以上,那就独自为其设置。相干配置形式: #默认公共超时hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=10000#独自为某个feign接口设置超时hystrix.command."FeignService#sayHello(String)".execution.isolation.thread.timeoutInMilliseconds=15000 B. 优化接口提供方的逻辑执行工夫。比方上述VipTradeReportFeignService#getShopTradeReportByDate中的for循环,是否移到接口调用方,相当于接口提供方每次只执行for循环的1次操作。说白了就是确保接口返回要在超时工夫内,这也合乎微服务接口的设计准则。 C. 还有种思路是接口解决异步化,即接口提供方立即返回,本人再用异步线程去解决最终逻辑。然而单纯这样会导致工作执行不牢靠,即接口返回胜利不代表实在肯定执行胜利了,如果此时接口提供方重启或异样导致耗时的异步逻辑执行一半就中断了,反而无奈利用分布式定时任务调度的机制去重试执行等。所以应用此思路时,接口立即返回但不能立即将工作也作为胜利执行结束,须要配合一些异步告诉机制,即接口提供方实在胜利完结耗时操作,告诉给接口调用方,接口调用方再将工作作为胜利返回上报。 2.2 feign.RetryableException failed to respond executing 异样这是C和D的异样,是随机低频告警。看字面意思是接口申请无响应,再联合邮件中的“熔断”字眼就天然揣测是接口提供利用的问题了(预先证实被“熔断”字眼坑了)。所以去追究接口所属利用pinka-mod-customer在告警前后的监控指标,发现tcp连贯、CPU、内存、网络流量体现都没什么异样情况。另外如果是熔断,那此接口必然得是调用失败屡次呀,而每次定时工作对该接口调用却只有一次。 这时候查看接口提供方Controller层日志,发现告警时刻的确提供方没进入controller解决。由此揣测,提供方利用自身并无问题。而查看调用方利用日志和性能指标,在那个时刻也无异常情况,还在一直向其余利用调用产生日志。再联合这个异样日志,揣测起因是因为调用方与提供方某次调用的网络闪断导致的(所以是随机低频)。 但为何会开启“熔断”,这个还无法解释。此时去追究邮件告警的代码源头,告警实质是通过重写了openfeign官网的HystrixCommand创立逻辑中的getFallback办法实现的,即进入fallback逻辑就会发邮件此时水落石出了,其实只是进了fallback降级,并不代表开启熔断,比方在HystrixCommand的run中抛出异样会进fallback,run执行超时会进fallback,熔断也会进fallback。即A~D这些异样,尽管邮件写的是熔断,但其实都没开启熔断,而只是进了fallback降级! 所以feign.RetryableException failed to respond executing这个其实只是一次偶尔的调用失败进了fallback而已,并没之前猜测的那么简单。 2.2.1 解决与思考邮件告警逻辑天然是要批改,辨别熔断和降级。如果要判断熔断,能够用如下办法 protected Object getFallback() { if (this.isCircuitBreakerOpen()) { // 熔断告警形式 sendExceptionEmail(...); }else{ // 非熔断降级告警,如果无需告警也可不写 sendExceptionEmail(...); } ....} “架构人生,迭代生命” ——高深老夏,搜寻summer_deep微信公众号可获取更多帮忙 ...

September 22, 2020 · 1 min · jiezi

关于spring:建议收藏阿里P7总结的Spring注解笔记把组件注册讲的明明白白

环境搭建注解的形式是通过配置类的形式来注入组件,注解注入要比XML注入的形式简略,注解注入也须要在前者的根底上,增加一个spring-context的包,也是理论开发中罕用的形式。 筹备所需Jar包 Spring注解之组件注册Spring提供了许多的注解配置,这样咱们就能够通过注解的形式实现组件的注册,下图就是Spring中常常应用到的注解。 @ComponentScan和@Configurable原先xml的形式 <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 要扫描的包 --> <context:component-scan base-package="model"></context:component-scan></beans>应用配置类@Configurable来标注该类为Spring中的配置类,@ComponentScan(“model”)是为该配置类指定要去扫描的参数。 package config;import org.springframework.beans.factory.annotation.Configurable;import org.springframework.context.annotation.ComponentScan;import model.Product;/** * @Configurable: 该注解是标注该类是配置类 * @ComponentScan:配置要扫描的包 * @author GaoYang */@Configurable@ComponentScan("model")public class MainConfig {}@Component应用该注解就能够将Java对象@Component注册到Ioc容器中,@Component注解要是给属性赋值要配合@Value注解为属性赋值。 /** @Componnt能够指定该对象的id,也能够不必指定 默认id为该类的类名首字母小写 */@Component("students")public class Student { @Value("01") private int sid; @Value("侯宁宁") private String name; @Value("男") private String sex;配置类 /** * @Configurable: 该注解是标注该类是配置类 * @ComponentScan:配置要扫描的包 * @author GaoYang */@Configurable@ComponentScan("model")public class MainConfig {}应用@Configuration注入 @Component("students")public class Student { @Value("01") private int sid; @Value("侯宁宁") private String name; @Value("男") private String sex; public Student() { super(); } public Student(int sid, String name, String sex) { super(); this.sid = sid; this.name = name; this.sex = sex; } public int getSid() { return sid; } public void setSid(int sid) { this.sid = sid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } @Override public String toString() { return "Student [sid=" + sid + ", name=" + name + ", sex=" + sex + "]"; }}测试 ...

September 22, 2020 · 5 min · jiezi

关于spring:一起来读官方文档SpringIOC05

1.5。bean 作用域创立bean定义时,将通过一个配方来创立该bean的理论实例。把bean定义解释称配方这一思维跟重要,因为它意味着与类一样,您能够从一个配方中创立许多对象实例。 bean definition 是用来形容bean的一个构造体,就像每个人体检指标一样,进出一趟医院能拿到体检单,bean在进入Spring流程中也会拿到属于本人的体检单。尽管医院不能依据体检单发明出人类,然而Spring能依据bean definition发明出实例您不仅能够管制从bean definition 创立的对象中的各种依赖项和配置值,还能够管制从特定bean定义创立的对象的作用域。 这种办法功能强大且灵便,因为您能够抉择通过配置创立的对象的作用域,而不用在Java类档次上解决对象的范畴。 能够将bean定义为部署在多种作用域中的一种。 Spring框架反对6种作用域,其中4种作用域只有在应用反对web的ApplicationContext时才可用。 您还能够创立自定义作用域。 Bean作用域范畴形容singleton(默认)单例对象,容器中只存在一个对象。prototype每次应用都会实例化新的对象request将单个bean定义的范畴限定为单个HTTP申请的生命周期。也就是说,每个HTTP申请都有一个bean实例。仅在反对web的Spring ApplicationContext上下文中无效。session每一次HTTP申请都会产生一个新的bean,同时该bean仅在以后HTTP session内无效。仅在可感知网络的Spring上下文中无效ApplicationContext。application将单个bean定义的作用域限定为的生命周期ServletContext。仅在可感知网络的Spring上下文中无效ApplicationContext。websocket将单个bean定义的作用域限定为的生命周期WebSocket。仅在可感知网络的Spring上下文中无效ApplicationContext。(这个scope没在源码中找到,暂不分明实现逻辑,但应该和之前的大同小异)从Spring 3.0开始,线程作用域可用,但默认状况下未注册。无关更多信息,请参见的文档 SimpleThreadScope。无关如何注册此自定义范畴或任何其余自定义范畴的阐明,请参阅 应用自定义范畴。 说一下大抵流程(非文档内容)https://gitee.com/cclookeme/tocmat-main贴一个git地址,这个工程演示如何用最简略的代码启动一个Spring利用,非SpringBoot拿进去大抵一说1.Tomcat启动会查找ServletContainerInitializer实现类并执行其中的onStartup办法。2.Spring-web模块存在ServletContainerInitializer实现类,所以Tomcat启动会调用Spring-web的代码。3.然而咱们用Spring框架的话不须要实现这个接口,实现一个Spring的接口WebApplicationInitializer。4.就能够由Tomcat调用Spring-web的ServletContainerInitializer实现类,再由Spring-web模块调用咱们的WebApplicationInitializer实现类//WebApplicationInitializer 实现形式如下(SpringMvc官网提供地址如下)//https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/web.html#spring-webpublic class MyWebApplicationInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletCxt) { // Load Spring web application configuration AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext(); ac.register(AppConfig.class); //ac.refresh(); 官网文档提供了这样一行代码然而咱们为了应用application Scope并不需要这个代码 // Create and register the DispatcherServlet DispatcherServlet servlet = new DispatcherServlet(ac); ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet); registration.setLoadOnStartup(1); registration.addMapping("/app/*"); }}有了如上代码,咱们就有了一个ApplicationContext环境。Tomcat启动见git我的项目就能够了,那个不重要。咱们就假设当初Tomcat曾经启动,启动并执行到咱们自定义的WebApplicationInitializer中了在这个自定义办法中咱们实例化了AnnotationConfigWebApplicationContext这个对象,把这个对象带进了DispatcherServlet,以至于ServletContext中以备后续应用,AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();ac.register(AppConfig.class);上边两行代码仅仅是指定了一个Config类,这个类上有很多注解相当于SpringBoot的启动类还有其余的参数须要Spring本人来进行解决,所有后续会有这个办法来丰盛ApplicationContextprotected WebApplicationContext initWebApplicationContext() { WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null; if (this.webApplicationContext != null) { // A context instance was injected at construction time -> use it wac = this.webApplicationContext; if (wac instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac; //这个办法只看这个中央 如果之前咱们自定义代码外面执行了ac.refresh() //那么这个中央的active会是true,那就没法进入if外面 //而if外面则是给ApplicationContext赋值了ServletContext //最初也会调用refresh办法 //而ServletContext的作用就是咱们的 application Scope //如果不注入ServletContext 则就无奈启用这个 Scope if (!cwac.isActive()) { if (cwac.getParent() == null) { cwac.setParent(rootContext); } configureAndRefreshWebApplicationContext(cwac); } } } . . . . return wac; } 在看一个refresh()里执行的代码public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory, @Nullable ServletContext sc) { beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope()); beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope()); //这里判断了sc sc就是上边咱们要注入的ServletContext 没注入的话这里就不注册解析 application Scope的bean if (sc != null) { ServletContextScope appScope = new ServletContextScope(sc); beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope); sc.setAttribute(ServletContextScope.class.getName(), appScope); } . . . }在之后具体Spring启动代码咱们不必看了咱们在看下Spring获取bean时候怎么解决的Scope//如果是单例 间接获取单例池中的对象 单例池中不存在执行createBean办法if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}else if (mbd.isPrototype()) { //如果是原型间接就createBean从新生成对象 Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}else { //其余Scope //首先获取以后bean的Scope String scopeName = mbd.getScope(); if (!StringUtils.hasLength(scopeName)) { throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'"); } //依据Scope获取解析以后Scope的bean //这里也就是给了咱们自定义Scope的可能 咱们能够本人定义Scope //再定义一个Scope的解析类就哦了 Scope scope = this.scopes.get(scopeName); //如果没找到解析类则报错 就像前边的ServletContext没注入一样 if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); } try { //这里的get是能够自定已实现缓存了,比方同一个request用一个实例 //雷同sessionId 用一个实例 //如果没找到对应的实例则createBean 生成 Object scopedInstance = scope.get(beanName, () -> { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } }); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); }}下边介绍各个Scope内容和用法(官网文档)1.5.1。 The Singleton Scope换句话说,当您定义一个bean定义并且它的作用域是一个单例对象时,Spring IoC容器会创立该bean定义定义的对象的一个实例。这个繁多实例存储在这样的单例bean的缓存中,对这个已命名bean的所有后续申请和援用都会返回缓存的对象。 ...

September 22, 2020 · 4 min · jiezi

关于spring:Jackson精解第4篇JacksonInject与JsonAlias注解

Jackson是Spring Boot(SpringBoot)默认的JSON数据处理框架,然而其并不依赖于任何的Spring 库。有的小伙伴认为Jackson只能在Spring框架内应用,其实不是的,没有这种限度。它提供了很多的JSON数据处理办法、注解,也包含流式API、树模型、数据绑定,以及简单数据类型转换等性能。它尽管简略易用,但相对不是小玩具,更多的内容我会写成一个系列,5-10篇文章,请您持续关注我。 《序列化与反序列化外围用法-JSON框架Jackson精解第1篇》《非凡数据格式解决-JSON框架Jackson精解第2篇》《属性序列化自定义排序与字母表排序-JSON框架Jackson精解第3篇》本节持续为大家介绍在JSON反序列化过程中,如何应用@JacksonInject注解和@JsonAlias注解 一、@JacksonInject注解在应用JSON格局进行反序列化的时候,咱们常常有这样一些需要。咱们从客户端或者其余渠道获取了一个JSON格局的数据对象,该对象蕴含若干个属性。然而咱们在将JSON字符串反序列化的时候,须要给它加上一些默认数据,比方: responseTime数据响应工夫,赋值为以后工夫即可;数据反序列化的操作人,赋值为零碎以后用户等客户端返回给咱们的数据自身不会携带这些附加信息,这个时候咱们就能够应用JacksonInject注解,在JSON字符串反序列化为对象的时候,加上这些附加信息。上面是JacksonInject应用办法 @Datapublic class PlayerStar { private String name; private Integer age; private String[] hobbies; //业余爱好,数组 private List<String> friends; // 敌人 private Map<String, BigDecimal> salary; //年收入 Map @JacksonInject("responseTime") //留神这里 private LocalDateTime responseTime;}咱们来测试一下反序列化的过程,须要留神的是下文中的jsonInString中并不携带responseTime信息,是咱们本人在反序列化的时候注入到java对象中的。 @Testvoid testJSON2Object() throws IOException { //为responseTime赋值为以后值 InjectableValues.Std iv = new InjectableValues.Std(); iv.addValue("responseTime", LocalDateTime.now()); ObjectMapper mapper = new ObjectMapper(); mapper.setInjectableValues(iv); //将可插入值,在反序列化过程中赋值给对象 //将JSON字符串反序列化为java对象 String jsonInString = "{\"name\":\"乔丹\",\"age\":45,\"hobbies\":[\"高尔夫球\",\"棒球\"]}"; PlayerStar jordan = mapper.readValue(jsonInString, PlayerStar.class); System.out.println(jordan);}最终的反序列化后果,java 对象的toString()办法输入后果如下,能够看到多出一个responseTime赋值属性,值为以后工夫 ...

September 22, 2020 · 1 min · jiezi

关于spring:Spring-5-中文解析数据存储篇Transactional使用

Spring外围篇章: Spring 5 中文解析之外围篇-IoC容器 Spring 5 中文解析外围篇-IoC容器之依赖关系 Spring 5 中文解析外围篇-IoC容器之Bean作用域 Spring 5 中文解析外围篇-IoC容器之自定义Bean性质 Spring 5 中文解析外围篇-IoC容器之BeanDefinition继承与容器拓展点 Spring 5 中文解析外围篇-IoC容器之基于注解的容器配置 Spring 5 中文解析外围篇-IoC容器之类门路扫描和组件治理 Spring 5 中文解析外围篇-IoC容器之JSR330规范注解 Spring 5 中文解析外围篇-IoC容器之基于Java容器配置 Spring 5 中文解析外围篇-IoC容器之Environment形象 Spring 5 中文解析外围篇-IoC容器之ApplicationContext与BeanFactory Spring 5 中文解析外围篇-IoC容器之Resources Spring 5 中文解析外围篇-IoC容器之数据校验、数据绑定和类型转换 Spring 5 中文解析外围篇-IoC容器之SpEL表达式 Spring 5 中文解析外围篇-IoC容器之AOP编程(上)") Spring 5 中文解析外围篇-IoC容器之AOP编程(下)") Spring 5 中文解析外围篇-IoC容器之Spring AOP API Spring测试篇章: Spring 5 中文解析测试篇-Spring测试 Spring 5 中文解析外围篇-集成测试之概要和集成测试注解 Spring 5 中文解析外围篇-集成测试之TestContext(上)") Spring 5 中文解析外围篇-集成测试之TestContext(中)") ...

September 21, 2020 · 2 min · jiezi

关于spring:Spring-boot-启动提示数据源错误

在启动 Spring Boot 的我的项目的时候提醒数据源未配置的谬误。 09:52:08.333 [main] DEBUG o.s.b.d.LoggingFailureAnalysisReporter - Application failed to start due to an exceptionorg.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Failed to determine a suitable driver class at org.springframework.boot.autoconfigure.jdbc.DataSourceProperties.determineDriverClassName(DataSourceProperties.java:233) at org.springframework.boot.autoconfigure.jdbc.DataSourceProperties.initializeDataSourceBuilder(DataSourceProperties.java:174) Spring 会提醒你残缺的导致启动谬误的信息是: ***************************APPLICATION FAILED TO START***************************Description:Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.Reason: Failed to determine a suitable driver classAction:Consider the following: If you want an embedded database (H2, HSQL or Derby), please put it on the classpath. If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).Process finished with exit code 1 谬误剖析从下面的启动信息来看,曾经说得十分分明了,就是因为你配置了 Spring 的数据组件,然而你没有配置相应的数据源。 ...

September 21, 2020 · 1 min · jiezi

关于spring:别再用swagger了给你推荐几个文档生成神器

最近公司打算做一个openapi开放平台,让我找一款好用的在线文档生成工具,具体要求如下: 1.必须是开源的 2.可能实时生成在线文档 3.反对全文搜寻 4.反对在线调试性能 5.界面柔美 说实话,这个需要看起来简略,然而实际上一点的都不简略。 我花了几天工夫到处百度,谷歌,技术博客 和 论坛查资料,先后调研了如下文档生成工具: 一、gitbookgithub地址:https://github.com/GitbookIO/... 开源协定:Apache-2.0 License Star: 22.9k 开发语言:javascript 用户:50万+ 示例地址:https://www.servicemesher.com... GitBook是一款文档编辑工具。它的性能相似金山WPS中的Word或者微软Office中的Word的文档编辑工具。它能够用来写文档、建表格、插图片、生成pdf。当然,以上的性能WPS、Office可能做得更好,然而,GitBook还有更最弱小的性能:它能够用文档建设一个网站,让更多人理解你写的书,另外,最最外围的是,他反对Git,也就意味着,它是一个分布式的文档编辑工具。你能够随时随地来编写你的文档,也能够多人独特编写文档,哪怕多人编写同一页文档,它也能记录每个人的内容,而后通知你他们之间的区别,也能记录你的每一次改变,你能够查看每一次的书写记录和变动,哪怕你将文档都删除了,它也能找回来!这就是它继承Git后的厉害之处! 长处:应用起来非常简单,反对全文搜寻,能够跟git完满集成,对代码无任何嵌入性,反对markdown格局的文档编写。 毛病:须要独自保护一个文档我的项目,如果接口批改了,须要手动去批改这个文档我的项目,不然可能会呈现接口和文档不统一的状况。并且,不反对在线调试性能。 集体倡议:如果对外的接口比拟少,或者编写之后不会常常变动能够用这个。 二、smartdocgitee地址:https://gitee.com/smart-doc-t... 开源协定:Apache-2.0 License Star: 758 开发语言:html、javascript 用户:小米、科大讯飞、1加 示例地址:https://gitee.com/smart-doc-t... smart-doc是一个java restful api文档生成工具,smart-doc颠覆了传统相似swagger这种大量采纳注解侵入来生成文档的实现办法。smart-doc齐全基于接口源码剖析来生成接口文档,齐全做到零注解侵入,只须要依照java规范正文的写就能失去一个规范的markdown接口文档。 长处:基于接口源码剖析生成接口文档,零注解侵入,反对html、pdf、markdown格局的文件导出。 毛病:须要引入额定的jar包,不反对在线调试 集体倡议:如果实时生成文档,然而又不想打一些额定的注解,比方:应用swagger时须要打上@Api、@ApiModel等注解,就能够应用这个。 三、redocgithub地址:https://github.com/Redocly/redoc 开源协定:MIT License Star: 10.7K 开发语言:typescript、javascript 用户:docker、redocly 示例地址:https://docs.docker.com/engin... redoc本人号称是一个最好的在线文档工具。它反对swagger接口数据,提供了多种生成文档的形式,非常容易部署。应用redoc-cli可能将您的文档捆绑到零依赖的 HTML文件中,响应式三面板设计,具备菜单/滚动同步。 长处:十分不便生成文档,三面板设计 毛病:不反对中文搜索,分为:一般版本 和 付费版本,一般版本不反对在线调试。另外UI交互个人感觉不适宜国内大多数程序员的操作习惯。 集体倡议:如果想疾速搭建一个基于swagger的文档,并且不要求在线调试性能,能够应用这个。 四、knife4jgitee地址:https://gitee.com/xiaoym/knife4j 开源协定:Apache-2.0 License Star: 3k 开发语言:java、javascript 用户:未知 示例地址:http://swagger-bootstrap-ui.x... knife4j是为Java MVC框架集成Swagger生成Api文档的加强解决方案,前身是swagger-bootstrap-ui,取名kni4j是心愿她能像一把匕首一样玲珑,轻量,并且性能强悍。 长处:基于swagger生成实时在线文档,反对在线调试,全局参数、国际化、拜访权限管制等,性能十分弱小。 ...

September 21, 2020 · 1 min · jiezi

关于spring:Angular短信模板校验代码

1、短信模板内容验证码 ${username} 12345验证码 ${username} 12345验证码 ${username} 12345从代码中提取 username, 并判断验证码 username中只存在英文字母 2、内容校验,提取模板中${}的内容并且,内容只能应用英文smsTemplateContentChange(value){ // 短信模板内容 校验 const error = this.smsTemplateForm.get('templateContent').getError('pattern'); if (error){ return; }else{ this.smsTemplateForm.get('templateContent').setErrors(null); } const reg = /\$\{((?!\{).)*\}/g; const matchStr = value.match(reg); const resultList = new Set(); this.paramsList = new Set(); const pattern = '^[a-zA-Z]{1,}$'; const regex = new RegExp(pattern); let isError = false; if (matchStr){ matchStr.forEach((item: string) => { const result = item.replace('${', '').replace('}', ''); if (!result.match(regex)){ isError = true; } resultList.add(result); }); if (isError){ // 设置错误信息 this.smsTemplateForm.get('templateContent').setErrors({errorParams: '参数只能应用英文'}); }else{ this.paramsList = resultList; } } // console.log(value.match(reg).replace('${', '').replace('}', '')); }3、前端html<se label="短信模板" [error]="{ required: '请输出短信模板', pattern: '最大长度不超过200!', errorParams: '${}参数中只能应用英文'}"> <textarea formControlName="xxx" [(ngModel)]="smsTemplateVo.xxx" (ngModelChange)="smsTemplateContentChange(smsTemplateVo.xxx)" nz-input required></textarea> <div ><strong>提取可用参数:</strong><nz-tag *ngFor="let tag of paramsList" nzColor="default">{{tag}}</nz-tag></div> </se>4、最终成果 ...

September 21, 2020 · 1 min · jiezi

关于spring:属性序列化自定义与字母表排序JSON框架Jackson精解第3篇

Jackson是Spring Boot默认的JSON数据处理框架,然而其并不依赖于任何的Spring 库。有的小伙伴认为Jackson只能在Spring框架内应用,其实不是的,没有这种限度。它提供了很多的JSON数据处理办法、注解,也包含流式API、树模型、数据绑定,以及简单数据类型转换等性能。它尽管简略易用,但相对不是小玩具,更多的内容我会写成一个系列,5-10篇文章,请您持续关注我。 《序列化与反序列化外围用法-JSON框架Jackson精解第一篇》 一、根底数据筹备二、序列化办法三、反序列化办法四、字段重命名@JsonProperty五、疏忽null字段的序列化@JsonInclude六、疏忽指定的字段《非凡数据格式解决-JSON框架Jackson精解第2篇》 一、从URL读取JSON数据二、Unknow Properties 赋值失败解决三、未赋值Java Bean序列化四、日期格式化大家在平时进行JSON数据序列化过程中,常常会有依照肯定程序序列化属性这样的需要。本文为大家介绍如何对JSON序列化的属性进行排序,能够自定义程序,也能够依照字母表程序排序。 一、@JsonPropertyOrder属性排序通过JsonPropertyOrder注解指定java POJO中各个成员变量的属性序列化程序。 @Data@JsonPropertyOrder({"salary","name","age","hobbies","friends"})public class PlayerStar { private String name; private Integer age; private String[] hobbies; //业余爱好,数组 private List<String> friends; // 敌人 private Map<String, BigDecimal> salary; //年收入 Map}最终Java POJO对象序列化为如下的字符串,属性是依照JsonPropertyOrder注解定义的程序序列化的("salary","name","age","hobbies","friends")。如果不应用JsonPropertyOrder指定程序,默认是依照Java类成员变量的申明程序进行序列化。 { "salary" : { "2000" : 10000000, "2010" : 62000000, "2020" : 112400000 }, "name" : "乔丹", "age" : 45, "hobbies" : [ "高尔夫球", "棒球" ], "friends" : [ "kobe", "curry", "james" ]}能够应用上面的代码将PlayerStar对象序列化为字符串 ...

September 21, 2020 · 1 min · jiezi

关于spring:SpringBoot动态注入及操作Bean

在Spring中咱们通过getBean来取得对象,但这些对象都是当时定义好的,如果须要操作当时未定义的Bean就须要动静注入、批改和删除Bean 思路在Spring中,BeanFactory负责管理Bean,具体来说是DefaultListableBeanFactory,咱们只须要获取到以后上下文中的BeanFactory,就能执行其中的注册Bean的办法registerBeanDefinition,注册Bean时须要Bean的信息,Spring提供了BeanDefinitionBuilder.genericBeanDefinition()办法来构建BeanDefinition,用这些办法就能够实现Bean的动静注入 代码实现测试服务类TestService创立一个测试类来测试Bean的操作,这个类上没有加注解,Spring在加载时不会主动注入 package com.mantis.bean.service;/** * @Description: * @author: wei.wang * @since: 2020/9/17 12:53 * @history: 1.2020/9/17 created by wei.wang */public class TestService { private String name; private String id; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void print() { System.out.println("获取bean,name=" + name + ",id=" + id); } @Override public String toString() { return "TestService{" + "name='" + name + '\'' + ", id='" + id + '\'' + '}'; }}SpringContextUtil类操作Bean的Util类,其中上线文ApplicationContext在SpringBoot启动时设置,也能够间接应用Autowired注入或者依据具体我的项目具体实现 ...

September 20, 2020 · 3 min · jiezi

关于spring:URL及日期等特殊数据格式处理JSON框架Jackson精解第2篇

Jackson是Spring Boot默认的JSON数据处理框架,然而其并不依赖于任何的Spring 库。有的小伙伴认为Jackson只能在Spring框架内应用,其实不是的,没有这种限度。它提供了很多的JSON数据处理办法、注解,也包含流式API、树模型、数据绑定,以及简单数据类型转换等性能。它尽管简略易用,但相对不是小玩具,本节为大家介绍Jackson的根底外围用法,更多的内容我会写成一个系列,5-10篇文章,请您持续关注我。 在 《序列化与反序列化外围用法-JSON框架Jackson精解第一篇》 也就是上一篇中,为大家介绍了这些内容 一、根底筹备二、序列化办法三、反序列化办法四、字段重命名@JsonProperty五、疏忽null字段的序列化@JsonInclude六、疏忽指定的字段本篇文章中为大家介绍,一些非凡JOSN数据格式解决-JSON框架Jackson精解第2篇: 一、从URL读取JSON数据二、Unknow Properties 赋值失败解决三、未赋值Java Bean序列化四、日期格式化一、从URL读取JSON数据Jackson不仅能够将字符串反序列化为 Java POJO对象,还能够申请近程的API,取得近程服务的JSON响应后果,并将其转换为Java POJO对象。 @Testvoid testURL() throws IOException { URL url = new URL("https://jsonplaceholder.typicode.com/posts/1"); //近程服务URL ObjectMapper mapper = new ObjectMapper(); //从URL获取JSON响应数据,并反序列化为java 对象 PostDTO postDTO = mapper.readValue(url, PostDTO.class); System.out.println(postDTO);}jsonplaceholder.typicode.com 是一个收费提供HTTP测试服务的网站,咱们能够利用它进行测试近程服务API返回后果是一个JSON字符串,一篇post稿件蕴含userId,id,title,content属性PostDTO 是咱们本人定义的java 类,同样蕴含userId,id,title,content成员变量下文是控制台打印输出后果,postDTO的toString()办法输入。 PostDTO(userId=1, id=1, title=sunt aut facere repellat provident occaecati excepturi optio reprehenderit, body=quia et suscipitsuscipit recusandae consequuntur expedita et cumreprehenderit molestiae ut ut quas totamnostrum rerum est autem sunt rem eveniet architecto)二、Unknow Properties 赋值失败解决有的时候,客户端提供的JSON字符串属性,多于咱们服务端定义的java 类的成员变量。 ...

September 20, 2020 · 2 min · jiezi

关于spring:Spring-面试题整理

Spring什么是 Spring 框架?Spring 是一个轻量级的 IOC 和 AOP 容器框架。是为 Java 应用程序提供基础性服务的一套框架,目标是用于简化企业应用程序的开发,它使得开发者只须要关怀业务需要。常见的配置形式有三种:基于 XML 的配置、基于注解的配置、基于 Java 的配置。 次要由以下几个模块组成: Spring Core:外围类库,提供 IOC 服务;Spring Context:提供框架式的 Bean 拜访形式,以及企业级性能(JNDI、定时工作等);Spring AOP:AOP 服务;Spring DAO:对 JDBC 的形象,简化了数据拜访异样的解决;Spring ORM:对现有的 ORM 框架的反对;Spring Web:提供了根本的面向 Web 的综合个性,例如多方文件上传;Spring MVC:提供面向 Web 利用的 Model-View-Controller 实现。如何了解 Spring 的 AOP?AOP 能够说是对OOP的补充和欠缺。OOP 引入封装、继承和多态性等概念来建设一种对象层次结构,用以模仿公共行为的一个汇合。当咱们须要为扩散的对象引入公共行为的时候,OOP 则显得无能为力。也就是说,OOP 容许你定义从上到下的关系,但并不适宜定义从左到右的关系。例如日志性能。日志代码往往程度地分布在所有对象档次中,而与它所分布到的对象的外围性能毫无关系。在 OOP 设计中,它导致了大量代码的反复,而不利于各个模块的重用。AOP 是面向切面编程, 将程序中的穿插业务逻辑(比方平安,日志,事务等),封装成一个切面,而后注入到指标对象(具体业务逻辑)中去。 AOP 的实现形式织入:指代码切入到指标函数的过程,例如 aspectJ 到 java 程序的过程称为织入。 动态AOP在编译期,切面间接以字节码的模式编译到指标字节码文件中。AspectJ 属于动态 AOP,是在编译时进行加强,会在编译的时候将 AOP 逻辑织入到代码中,须要专有的编译器和织入器。 动静AOP实现原理是为被代理的业务接口生成代理类,将AOP逻辑写入到代理类中,在运行时动静织入AOP,应用反射执行织入的逻辑。  次要实现形式依赖 java.lang.reflect 包下的 InvocationHandler 和 Proxy 类。 ...

September 18, 2020 · 1 min · jiezi

关于spring:Springboot-框架整理建议做开发的都看看整理的比较详细

什么是 Spring Boot?SpringBoot是Spring我的项目中的一个子工程,与咱们所熟知的Spring-framework 同属于spring的产品,是用来简化 spring 初始搭建和开发过程应用特定的形式进行配置,创立了独立的 spring 援用程序 main 办法运行。同时SpringBoot中镶入了 Tomcat 无需部署 war 包间接打成 jar 包 nohup java -jar – & 启动就好,简化了 maven 的配置,主动配置 spring 增加对应的 starter 自动化配置。 Spring Boot 有哪些长处?缩小开发,测试工夫应用 JavaConfig 有助于防止应用 XML。防止大量的 Maven 导入和各种版本抵触。提供意见倒退办法。通过提供默认值疾速开始开发。没有独自的 Web 服务器须要。这意味着你不再须要启动 Tomcat,Glassfish或其余任何货色。须要更少的配置 因为没有 web.xml 文件。只需增加用@ Configuration 正文的类,而后增加用@Bean 正文的办法,Spring 将主动加载对象并像以前一样对其进行治理。您甚至能够将@Autowired 增加到 bean 办法中,以使 Spring 主动装入须要的依赖关系中。基于环境的配置 应用这些属性,您能够将您正在应用的环境传递到应用程序:-Dspring.profiles.active = {enviornment}。在加载主应用程序属性文件后,Spring 将在(application{environment} .properties)中加载后续的应用程序属性文件。SpringBoot和SpringMVC区别?SpringBoot 是一个疾速开发的框架,可能疾速的整合第三方框架,简化XML配置,全副采纳注解模式,内置Tomcat容器,帮忙开发者可能实现疾速开发,SpringBoot的Web组件 默认集成的是SpringMVC框架。SpringMVC是管制层。 SpringBoot疾速入门1.创立工程咱们先新建一个空的demo工程,如下: 2.在pom.xml引入依赖 在pom.xml中引入spring-boot-start-parent,spring官网的解释叫什么stater poms,它能够提供dependency management,也就是说依赖治理,引入当前在申明其它dependency的时候就不须要version了,前面能够看到。SpringBoot提供了一个名为spring-boot-starter-parent的工程,外面曾经对各种罕用依赖(并非全副)的版本进行了治理,咱们的我的项目须要以这个我的项目为父工程,这样咱们就不必操心依赖的版本问题了,须要什么依赖,间接引入坐标即可! 启动测试 ...

September 18, 2020 · 1 min · jiezi

关于spring:JSON数据处理框架Jackson精解第一篇序列化与反序列化核心用法

Jackson是Spring Boot默认的JSON数据处理框架,然而其并不依赖于任何的Spring 库。有的小伙伴认为Jackson只能在Spring框架内应用,其实不是的,没有这种限度。它提供了很多的JSON数据处理办法、注解,也包含流式API、树模型、数据绑定,以及简单数据类型转换等性能。它尽管简略易用,但相对不是小玩具,本节为大家介绍Jackson的根底外围用法,更多的内容我会写成一个系列,5-10篇文章,请您持续关注我。 一、根底筹备在任意我的项目中引入上面的jar就能够应用jackson进行JSON的数据序列化与反序列化的性能。 <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.8</version></dependency>写一个PlayerStar的实体类,实体类次要体现篮球明星的名字、年龄、业余爱好、敌人、年收入等信息,为了尽可能地演示Jackson的序列化与反序列化性能,将数组、List、Map都交融到这个类外面。并通过getInstance初始化篮球明星Jordan这个对象。 @Datapublic class PlayerStar { private String name; private Integer age; private String[] hobbies; //业余爱好,数组 private List<String> friends; // 敌人 private Map<String, BigDecimal> salary; //年收入 Map //初始化一个对象用于测试 public static PlayerStar getInstance(){ PlayerStar playerStar = new PlayerStar(); playerStar.setName("乔丹"); playerStar.setAge(45); playerStar.setHobbies(new String[]{"高尔夫球", "棒球"}); Map<String, BigDecimal> salary = new HashMap<String, BigDecimal>() {{ put("2000", new BigDecimal(10000000)); put("2010", new BigDecimal(62000000)); put("2020", new BigDecimal(112400000)); }}; playerStar.setSalary(salary); playerStar.setFriends(Arrays.asList("kobe", "curry", "james")); return playerStar; }}二、序列化办法上面代码演示了如何将PlayerStar对象序列化为JSON字符串。 ...

September 17, 2020 · 2 min · jiezi

关于spring:Spring-5-中文解析数据存储篇理解Spring事物抽象

Spring外围篇章: Spring 5 中文解析之外围篇-IoC容器 Spring 5 中文解析外围篇-IoC容器之依赖关系 Spring 5 中文解析外围篇-IoC容器之Bean作用域 Spring 5 中文解析外围篇-IoC容器之自定义Bean性质 Spring 5 中文解析外围篇-IoC容器之BeanDefinition继承与容器拓展点 Spring 5 中文解析外围篇-IoC容器之基于注解的容器配置 Spring 5 中文解析外围篇-IoC容器之类门路扫描和组件治理 Spring 5 中文解析外围篇-IoC容器之JSR330规范注解 Spring 5 中文解析外围篇-IoC容器之基于Java容器配置 Spring 5 中文解析外围篇-IoC容器之Environment形象 Spring 5 中文解析外围篇-IoC容器之ApplicationContext与BeanFactory Spring 5 中文解析外围篇-IoC容器之Resources Spring 5 中文解析外围篇-IoC容器之数据校验、数据绑定和类型转换 Spring 5 中文解析外围篇-IoC容器之SpEL表达式 Spring 5 中文解析外围篇-IoC容器之AOP编程(上)") Spring 5 中文解析外围篇-IoC容器之AOP编程(下)") Spring 5 中文解析外围篇-IoC容器之Spring AOP API Spring测试篇章: Spring 5 中文解析测试篇-Spring测试 Spring 5 中文解析外围篇-集成测试之概要和集成测试注解 Spring 5 中文解析外围篇-集成测试之TestContext(上)") Spring 5 中文解析外围篇-集成测试之TestContext(中)") ...

September 16, 2020 · 2 min · jiezi

关于spring:Spring-5-中文解析数据存储篇Spring框架的事物支持模型的优势

Spring外围篇章: Spring 5 中文解析之外围篇-IoC容器 Spring 5 中文解析外围篇-IoC容器之依赖关系 Spring 5 中文解析外围篇-IoC容器之Bean作用域 Spring 5 中文解析外围篇-IoC容器之自定义Bean性质 Spring 5 中文解析外围篇-IoC容器之BeanDefinition继承与容器拓展点 Spring 5 中文解析外围篇-IoC容器之基于注解的容器配置 Spring 5 中文解析外围篇-IoC容器之类门路扫描和组件治理 Spring 5 中文解析外围篇-IoC容器之JSR330规范注解 Spring 5 中文解析外围篇-IoC容器之基于Java容器配置 Spring 5 中文解析外围篇-IoC容器之Environment形象 Spring 5 中文解析外围篇-IoC容器之ApplicationContext与BeanFactory Spring 5 中文解析外围篇-IoC容器之Resources Spring 5 中文解析外围篇-IoC容器之数据校验、数据绑定和类型转换 Spring 5 中文解析外围篇-IoC容器之SpEL表达式 Spring 5 中文解析外围篇-IoC容器之AOP编程(上)") Spring 5 中文解析外围篇-IoC容器之AOP编程(下)") Spring 5 中文解析外围篇-IoC容器之Spring AOP API Spring测试篇章: Spring 5 中文解析测试篇-Spring测试 Spring 5 中文解析外围篇-集成测试之概要和集成测试注解 Spring 5 中文解析外围篇-集成测试之TestContext(上)") Spring 5 中文解析外围篇-集成测试之TestContext(中)") ...

September 16, 2020 · 1 min · jiezi

关于spring:有关SpringMVC分层

软件为什么要分层? 首先要有一个背景:在一个大型软件系统设计时,业务个别绝对简单,不像一个HelloWord写到一个类外面就能够了,比方说求整数的和,求某个范畴之内基数的和偶数的和,这些否是一些比拟小的话题,还比方说银行外面的业务包含还有保险这块证券这块你会发现就是字段业务数据都谁非常复杂,那么如果所有的业务代码都写到一个类外面都纠缠在一起就会呈现逻辑不清晰,可读性差,保护艰难.那么也就是在一个祝贺外面也一样,把所有的事件都交给一个人来做,比方说老师我这网络断了,老师我这个电脑怎么这么卡顿啊,老师我的椅子换了,女朋友跟我离别了,那你想一想老师明天没有什么情绪去讲技术问题了,所以说这外面程序也是一样的.当一个类你让它去做太多太多事件的时候,那么这个类外面的代码量就会越来越多越来越多,导致逻辑不清晰,可读性还差,保护起来还艰难.那么还能够触发这样一种事件,就是改变一处很多中央相关联的中央都得去改,你比方说一个类外面你既有管制逻辑又有数据逻辑,还有业务逻辑,还有页面显示逻辑等等等.你把所有的这些性能都放到一个类外面去实现,那这个代码就没法看了,为了更好的去解决这样一个问题,有了咱们所说的分层架构设计,晚期最早的时候咱们的软件其实都非常简单,以前写一个企业介绍做一个网页最后的时候就做一个网页而已,而且这个网页上没有都没有动静的只有动态的一个页面,可能应用html/css/js,加起来几张图片,显示一下这个企业的介绍就能够了,当初要求在这个网页上进行注册,在互联网下面进行答疑,在互连网上进行领取,你会发现互联网软件的需要在变,而后呢咱们随着需要的变动咱们的代码也须要变,退出吧代码都写到一个类外面,你可能在这个类外面改呀改呀改呀,就十分十分不容易去对这个类进行保护了,分层设计就当诞生了.那为什么要有这种分层设计呢,分层设计的实质其实严格来讲就是将简单问题简单化,首先基于繁多准则让每个对象各司其职各尽所能,而后基于高内聚低耦合,分层当前,其实每个对象都有本人的一个职责.然而最终咱们要把这些对象融到一起,通过对象这边的协同来解决问题,就相似于公司外面咱们有很多部门,比方说有职业发展部有教学部,有咨询部有就业部等等,然而最终这些部门要协同来服务于各位同学,让各位同学找一份好的工作,所以在这里呢要看,程序中也是一样的,尽管咱们把这个性能也就是把咱们这个类啊把不同的性能封到了不同的模块当中,然而咱们最终这些模块这些对象还要耦合在一起,然而如何耦合呢?咱们要低耦合高内聚,高内聚就是把这个职责不要外露,你本人的就是你本人的,比方说待业的事件不能交给咱们教学部,那职业发展部的事件也交给咱们教学部,那必定不行.高内聚就是把你本人的业务先理清.你本人的业务是那一部分?首先要理出个123来,你的业务范围是什么;而后前面咱们这个低耦合,不是你要解决的业务,是他人要解决的业务,然而咱们这两个业务模块要协同,那这个时候怎么协同,通过接口,就是所谓的高内聚低耦合,这种设计思维实现相干层对象之间的交互,能够进步程序的可维护性和可扩展性.但有的时候提到这点,写代码写的写的同学他意识不到这个问题,就相似于共享单车,最开始咱们可能拿手机扫码,扫码当前还须要手动去开锁,但当初蓝牙放开了当前,只有手机去扫码,蓝牙是开的,能够主动开锁.这就是需要的变动,那咱们如何基于需要的变动让咱们的软件可能在不批改或大量批改代码的状况下就可能满足这种需要,这就是可扩展性. 通信畛域的OSI参考模型接触过TCP/IP协定,它是个分层协定,它是那一层呢?网络中还有典型的OSI参考模型,这个你们理解,就是互联网这个畛域外面也有一个分层设计,比方说应用层>表示层>会话层>传输层>网络层>链路层>物理层其实严格来讲,咱们在互联网中传输数据的时候就是这样来传输的.首先是应用层往下走,也就是说你从网络中的一端传到另外一端把这个音讯,它是有这么一个分层音讯.这个其实到物理层传输的就是比特流:二进制数据,那么这个分层也就是说OSI参考模型它对应的一个简化模型其实就是咱们所说的TCP/IP典型的四层模型.在这四层模型外面下面就是把这个应用层/表示层/会话层演绎为应用层,你像咱们在浏览器外面输出HTTP协定:http://www.baidu.com各位同学...传递就是UDP协定.那未来你可能说咱们这个TCP咱们叫数据传输层,UDP也是数据传输层,未来你这个数据是不是要通过网络进行传输那还得有一个IP网络层(IP地址),而后最终是咱们的网络接口层,其实网络接口层就是把链路层和物理层和为了一层.其实底层咱们手机打电话就用到了TCP/IP协定, 咱们互联网外面的分层架构-----在上图箭头示意的是一种依赖关系,就是下面这层依赖于上面这层,上节课咱们在这写了GoodsService依赖于GoodsDao这叫依赖has a的关系.凋谢接口层依赖于Web层,也能够依赖于咱们的Service层.如果说未来咱们做微服,做分布式架构那么可能多个零碎,那零碎与零碎之间要进行通信,咱们当初正在做的是一个零碎,那未来零碎与零碎之间须要通信吗?也须要基于Java的互联网架构,在进行分层设计时,首先要对整体的零碎分层架构有一个根本意识.整体分层怎么了解呢?第一个,这一层你们总是意识的吧,为咱们的操作系统是跑在硬件之上,你得有CPU(负责计算的),存储设备(存你的数据的),可能有外存内存就是你的磁盘也还,内存条也好,内存;还有一些网络设备,这个网络设备就不用说了吧,路由器交换机网线等等等等,那么在硬件层之上是谁?操作系统吧,操作系统是不是负责调度和治理你的硬件的呀?比方说操作系统把你的这个操作交给CPU,你在网络上要存储一个文件,比方说你在操作系统上 新建一个文件夹,word,文本,那个文本是不是存储到具体的某一块存储设备上,未来你的这个数据想从这一端传到另外一端是不是需不需要网络设备?须要也就是操作系统严格来讲就是调度和治理你的根底硬件层.操作系统上能够装Tomcat,未来能够装Redis,还有咱们的MQ,包含咱们数据库是装在操作系统下面的,你的操作系统是装在平台中间件层.还有应用软件层,比方说你的领取零碎利用零碎.就相似于各位同学你们用的TTS,其实都是放在Tomcat外面,在Tomcat中去运行,这就是一个中间件服务器,那么还有呢刚开始让你写操作系统难吗难,你写不进去,别说你写不出不来,整个中国有几个能把操作系统写进去的?没有,很少.还有平台中间件,比方说你们用过Tomcat,你们写过Tomcat吗?没有.然而有人去写吗?所说一些写平台的都是一些高级的软件工程师.那么这个下面,你写的这个领取零碎比方说有的同学写了一个永和门店零碎,那个永和门店零碎跑在谁的下面呀?Tomcat下面,没有Tomcat,没有相似的这样的web服务器,你写的那个软件是不是无用武之地呀,他得有运行的平台.而后在这个下面,在这种应用软件下面,可能就是接入层了,这个接入层指的是什么呢比方说网管呀,就相似于各位同学思考咱们要想间接拜访谷歌分让咱们拜访吗?拜访不了,国家在网管层面做了设置.你要想进来只能翻墙或者通过代理进来的未来咱们这个网管在这里它会有这么一个设计第一它有这么一个作用,就是要监控你这个拜访的入口,你要拜访哪里;第二,它要把你的申请分发给不同的服务吧,还有未来你们可能还会学到负载平衡,CDN,其实都属于软件的`接入层..未来咱们去拜访一个服务端的资源,就拿百度来讲,可能给你出现一个页面,js/css/html页面是不是须要从服务端传到客户端呀?然而有些动态资源长时间不变,那能不能把这些动态资源咱们放到本地的一个服务器上,就近的服务器上呢?有些公司就专门的卖这样的服务器资源叫CDN,把一些css/js就放在这下面了,这里想要你意识到大的软件分层. 其实咱们的软件整体分层,根底硬件层不要/操作系统是软件/Tomcat是软件/领取地图零碎是软件----咱们的根底硬件层是为咱们的下面的操作系统提供一个根底保障,下面的操作系统负责调度和治理硬件,那咱们的中间件装在操作系统下面,咱们的应用软件跑在中间件下面,前面你们要想拜访咱们的软件就得对它(接入层)进行管制吧. 在上图中,很多公司会依据雇员的技能专长进行相干分工,例如有运维工程师,中间件平台开发工程师,产品开发工程师,产品开发工程师,测试工程师等,咱们很多高级的java程序员次要从事的是产品开发或者是应用软件(例如可和关系管理系统,分销零碎,配送零碎,领取零碎等)开发,而在应用软件开发时,咱们个别也要进行分层设计,例如典型的MVC分层设计,咱们能够参考阿里巴巴开发手册中给出的分层设计模型, 其实咱们很多高级程序员刚开始做的是那一块?应用软件是最简略的.如果未来很多同学比方说我是计算机专业的,或者说我自学了计算机这门迷信,我理解操作系统,我理解计算机的组成原理,理解数据结构和算法,晓得数电模电等等,你会发现很多同学还能够写出这些Tomcat来,中间件,写平台.未来技术倒退到肯定的层面,就是写平台,就相似于阿里的王监博士,叫王监院士当初,他当初做了一个云平台(阿里云).当初很多的企业的服务都运行在阿里云下面,包含12306高峰期的时候都是租用阿里云的服务器.个别应用软件层端采纳的分层指的是MVC,仅仅是软件的分层,整体还有一个零碎分层.软件分层能够参考阿里巴巴的开发手册:终端显示层(显示数据的,就是V)--------申请解决层(就是解决咱们申请的数据,严格来讲这一块就是咱们MVC外面的C管制层)上面就是M业务逻辑,咱们写了一个业务逻辑goodsService,还写过goodsDao------------左边当初你不必思考这么多当初,因为未来咱们的零碎是不是也要提供一个凋谢接口有可能(咱们的软件当中要想显示一下天气预报信息,咱们公须要发射一个卫星到天上去监测天气情况吗? )你的零碎当中显示的天气信息来自官网的气象数据,官网的对外提供一个接口让咱们去调用啊?所以你那个才会显示进去,就相似于举个简略例子,咱们交了个车,DD软件上有一个地图 ,那地图不是它研发的,比方说是qq地图啊,那它就是调用了qq地图的性能.未来咱们的零碎可能要对外裸露一些接口,让别的零碎能够拜访咱们的接口进儿来获取咱们零碎中的数据.上面这个他人能够拜访咱们的零碎咱们是不是也能够拜访他人的零碎?就相似于咱们零碎当中想融入地图功能那咱们是不是应该去调用百度地图的接口啊? 首先第一个显示的是费用,你感觉它研发这个地图有什么用啊?你的软件中要想调用他人的接口就得交钱啊!你感觉我下载了一个百度地图没有问题啊,本人用没事,然而你要把这个地图嵌入到你们的软件中去那就得交接口使用费,很多公司做这个的,做标准做接口,其它的也是一样免费的. IOC是设计思维,MVC同样也属于一种设计思维.MVC(Model-view-controller)是软件共工程当中的一种软件架构模式,基于这样一种模式能够把软件系统分成三个根本局部:一个是模型,一个是视图,还有一个是controller,它也是一种分层设计,那么为什么也要分成这三个局部呢,也是各司其职,各尽所能吧,那视图用来做什么,用来实现与用户的交互,用来出现数据,管制层呢?那可能它要做的事件就是管制逻辑,这个管制逻辑就是申请和响应管制逻辑的一个实现,模型其实就是严格来讲是一个业务对象,你能够把它了解成用来解决业务逻辑和数据逻辑的一个对象,咱们通过这样的设计让咱们的构造看起来会更加的简洁直观,升高程序的复杂度,具体呢它也说了它每一个对象有什么职责,咱们在设计软件时通常要遵循这样的设计准则,这外面提到了首先是基于繁多职责准则,每个对象让它各尽其职各尽所能,而后基于高内聚低耦合实现对象之间的交互,那么在JavaEE体系这种MVC的设计思维是这样的,在JavaEE体系咱们讲的是,传统的没有任何的框架的状况下咱们须要有这样的一个意识:饿哦们的浏览器和咱们的手机端还有咱们的自行车段等等各种端等等当初都能够向服务端发动申请,这个服务端你能够看成是一个WebServer服务器(Tomcat...),那么申请过去的时候会通过一个对象,这个叫过滤器对象,对申请进行过滤,举个例子在今日头条或者字节跳动这个公司它有零碎各位同学也能够看到叫"灵犬零碎",可能很多人在做自媒体比方说在抖因上发个视屏,或者在今日头条上发个文章,如果这些视屏和文章都有咱们的人工去校验,那今日头条得招多少人啊? 那他就须要做这样的一个零碎,对戏你申请进行拦挡和过滤,你这个图片是否蕴含一些敏感信息呢?如果有可能就间接就给Pass掉了,就相似于我写这样的文章.所有的零碎都会有这样的,而咱们这个MVC设计的时候这外面这个过滤器吧filter它的作用是就是先对你的申请先做一个过滤,过滤完了当前交给谁呢?JavaEE体系外面学过Servlet技术,交给Servlet去对你的申请进行解决,而Servlet最外围的作用就是申请逻辑和响应逻辑的一个管制,你所有的数据达到咱们这个Servlet这当前,Servlet外面就能够拿到申请中的数据,基于你的申请去调用前面的对象来执行业务,你未来调用哪一个业务,你未来把这个业务执行完的后果用哪一个页面进行出现,都是Servlet说了算,你说我的申请达到Servlet当前由谁来帮我执行这个业务呢?Servlet在这里就起到控制器的作用.这种技术就是JSP+Servlet+JavaBean就是晚期咱们用的技术 没框架的状况下纯JavaEE体系,当初不是JavaEE外面生态做的越来越好么,各种框架呈现了所以就有了咱们MVC这种设计框架.Spring MVC属于Spring的WEB模块,它在设计的时候采纳了MVC这种设计思维,去简化程序员在Servlet这个对象当中,申请和响应数据的解决.就是有些数据在Servlet立面request.getParameter()获取申请参数,request.setCharacterEncoding()设置申请编码或者request.forward转发等等,它把这些通用的共性的货色在框架外面做了封装而已,次要是来简化这部分共性代码的编写. SpringMVC简化架构图:右边还是咱们的客户端,这部分过滤器一个是JavaEE标准当中定义了一个过滤器叫Filter,叫过滤器接口然而在不同的框架外面基于这个接口去写不同的实现类,比如说SpringMVC外面提供的CharacterEncodingFilter对字符编码进行过滤,进行解决这就是一个过滤器.DispatcherServlet(front controller)它实质就是一个Serclet,它是实现了Servlet这个接口的;如果Spring没有写或JavaEE当中废除了这接口,那么Spring中这个接口就作废了,因为这个类它是基于JavaEE标准第二阶段讲的Servlet来定义的.它外部封装了申请和响应的管制逻辑的实现,如果是传统的SpringMVC的我的项目,你还须要对这个类进行配置,然而到了这个SpringBoot当中这个类的配置都不必去写了,因为Spring谋求的指标是开箱即用,它把很多共性的配置也帮你去解决了.当咱们的申请过去当前,达到DispatcherServlet当前,那咱们晓得咱们申请中可能传一个url,谁来解决这个url呢?那前面呢咱们可能有一个后端控制器叫Handle(back controller)来解决你的申请.咱们可能会有很多url,那么不同的url对应不同的controller.womenqu1就举个简略例子,银行往往有一个大堂经理DispatherServlet(from controller),你想办什么业务?你是对公的还是对私的?办不同业务会有不同的营业人员来服务于你:银行会有营业厅,营业厅外面会有一些营业专员,那些营业专员是不是会服务于你的这些申请?那咱们怎么晓得呢?比方说DispatcherServlet这个对象它(HandleMapping)就得晓得,咱们哪些对象解决哪些申请得有吧,所以在下面它就有一个表格,表格外面就要注册着什么样的url有什么样的对象来解决,也就是什么样的申请有什么养的对象来解决.这个地位(HandleMapping)就有申请映射,不同的申请来解决不同的映射.国家最高的势力机构是国务院,国务院下边是不是还得管着政法委书记呀?那政法委书记还要管公安检察院还有法院.比方说有一个刑警想去抓一个人得有检察院来批捕.比方说政法委书记就会做这样的事件,它有一个抓人申请,抓人找刑警,这外面要有一个审判的过程去找法院,那它(DispatcherServlet)其实就是一个控制器.生存当中有很多很多这个逻辑和程序中1是香香的,所以这一块叫做注册核心, 一个班外面有技术班长,还有行政班长,你比方说有一个技术上的申请,看看是谁找到这个同学(HandleMapping)A(那这个地位其实就是一个注册核心,或者了解成记录,不同申请由不同对象来解决的一个对象)就是负责技术上申请的班长;你说你有一个行政上的,那这块行政班长去做.当咱们这个对象在解决之前,比如找到了谁来解决这个url(DispatcherServlet),找到了应该是由这个对象(Handle)来解决url,在解决这个url之前后面有个拦截器,这个也是一个非凡的过滤器也是一个非凡的拦截器,这个拦截器是SpringMVC中设计的它会做什么事件?举个简略例子:咱们在拜访12306的时候,早上06:00之后能够订票,早晨23:00之前能够订票,然而不在这个工夫范畴之内定不了票,这就是拦截器要做的事件,你能够在这边记录咱们管制层办法的执行工夫,你能够在这边去做咱们这个拜访拦挡都是它.但当初呢呢们可能没有讲过这个拦截器,在前面的内容中讲一讲,那咱们这个后端把数据把这个申请解决完了当前要的返回一个响应,这个响应给谁呢?还是给这个Servlet(DispatcherServlet),你的厨师做完了美味佳肴,把你这个饭给你做好了交给这个服务员,那服务员拿到这个当前该出现给哪一桌?在这个时候是不是它应该对咱们这个响应后果进行解决啊,那解决的时候有个view(viewResover),就要有个试图解析,如果你这边响应一个view,它(Handle)会对view进行解析,比方说加个前缀加个后缀.学MVC的时候有个视图解析器.然而我反悔了一个goods.html(加了一个后缀,再加一个前缀),门路加上咱们这个后缀再加上你这个view就造成了咱们这个view的残缺门路,最初把view相应到客户端.

September 15, 2020 · 1 min · jiezi

关于spring:不多bbSpringAOP源码解析切就完事了

一、AOP、SpringAOP、AspectJ的区别AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译形式和运行期间动静代理实现程序性能的对立保护的一种技术。利用AOP能够对业务逻辑的各个局部进行隔离,从而使得业务逻辑各局部之间的耦合度升高,进步程序的可重用性,同时进步了开发的效率。 文有文的,没用过的确很懵,然而用过之后,不说清晰,起码有点意思了。 Spring AOP:它基于动静代理来实现。默认的,如果应用接口的,用 JDK 提供的动静代理实现,如果没有接口,应用 CGLIB 实现。大家肯定要明确背地的意思,包含什么时候会不必 JDK 提供的动静代理,而用 CGLIB 实现。Spring 3.2 当前,spring-core 间接就把 CGLIB 和 ASM 的源码包含进来了,这也是为什么咱们不须要显式引入这两个依赖Spring 的 IOC 容器和 AOP 都很重要,Spring AOP 须要依赖于 IOC 容器来治理。如果你是 web 开发者,有些时候,你可能须要的是一个 Filter 或一个 Interceptor,而不肯定是 AOP。Spring AOP 只能作用于 Spring 容器中的 Bean,它是应用纯正的 Java 代码实现的,只能作用于 bean 的办法。Spring 提供了 AspectJ 的反对,前面咱们会独自介绍怎么应用,一般来说咱们用纯的 Spring AOP 就够了。很多人会比照 Spring AOP 和 AspectJ 的性能,Spring AOP 是基于代理实现的,在容器启动的时候须要生成代理实例,在办法调用上也会减少栈的深度,使得 Spring AOP 的性能不如 AspectJ 那么好。 AspectJ: AspectJ 出身也是名门,来自于 Eclipse 基金会,link:https://www.eclipse.org/aspectj ...

September 15, 2020 · 4 min · jiezi

关于spring:写的太细了Spring-MVC拦截器的应用建议收藏再看

Spring MVC拦截器拦截器是Spring MVC中弱小的控件,它能够在进入处理器之前做一些操作,或者在处理器实现后进行操作,甚至是在渲染视图后进行操作。 拦截器概述对于任何优良的MVC框架,都会提供一些通用的操作,如申请数据的封装、类型转换、数据校验、解析上传的文件、避免表单的屡次提交等。晚期的MVC框架将这些操作都写死在外围控制器中,而这些罕用的操作又不是所有的申请都须要实现的,这就导致了框架的灵活性有余,可扩展性升高SpringMVC提供了Interceptor拦截器机制,相似于Servlet中的Filter过滤器,用于拦挡用户的申请并做出相应的解决。比方通过拦截器来进行用户权限验证,或者用来判断用户是否曾经登录。Spring MVC拦截器是可插拔式的设计,须要某一性能拦截器,只需在配置文件中利用该拦截器即可;如果不须要这个性能拦截器,只需在配置文件中勾销利用该拦截器。在Spring MVC中定义一个拦截器有两种办法:实现HandlerInterceptor接口,实现WebRequestInterceptor接口.实现HandlerInterceptor接口首先来看看HandlerInterceor接口的源码,该接口位于org.springframework.web.servlet的包中,定义了三个办法,若要实现该接口,就要实现其三个办法: preHandle()办法:该办法在执行控制器办法之前执行。返回值为Boolean类型,如果返回false,示意拦挡申请,不再向下执行,如果返回true,示意放行,程序持续向下执行(如果前面没有其余Interceptor,就会执行controller办法)。所以此办法可对申请进行判断,决定程序是否继续执行,或者进行一些初始化操作及对申请进行预处理。 postHandle()办法:该办法在执行控制器办法调用之后,且在返回ModelAndView之前执行。因为该办法会在DispatcherServlet进行返回视图渲染之前被调用,所以此办法多被用于解决返回的视图,可通过此办法对申请域中的模型和视图做进一步的批改。 afterCompletion()办法:该办法在执行完控制器之后执行,因为是在Controller办法执行结束后执行该办法,所以该办法适宜进行一些资源清理,记录日志信息等解决操作。 实现了HandlerInterceptor接口之后,须要在Spring的类加载配置文件中配置拦截器实现类,能力使拦截器起到拦挡的成果,加载配置有两种形式: 针对HandlerMapping配置,样例代码如下: 这里为BeanNameUrlHandlerMapping处理器配置了一个interceptors拦截器链,该拦截器链蕴含了myInterceptor1和myInterceptor2两个拦截器,具体实现别离对应上面id为myInterceptor1和myInterceptor2的bean配置。 长处:此种配置的长处是针对具体的处理器映射器进行拦挡操作 毛病:毛病是如果应用多个处理器映射器,就要在多处增加拦截器的配置信息,比拟繁琐 针对全局配置,样例代码如下: 在下面的配置中,可在mvc:interceptors标签下配置多个拦截器其子元素 bean 定义的是全局拦截器,它会拦挡所有的申请;而mvc:interceptor元素中定义的是指定元素的拦截器,它会对指定门路下的申请失效,其子元素必须依照mvc:mapping --> mvc:exclude-mapping --> bean的程序,否则文件会报错。 实现WebRequestInterceptor接口WebRequestInterceptor中也定义了三个办法,也是通过这三个办法来实现拦挡的。这三个办法都传递了同一个参数WebRequest, WebRequest 是Spring 定义的一个接口,它外面的办法定义都根本跟HttpServletRequest 一样,在WebRequestInterceptor 中对WebRequest 进行的所有操作都将同步到HttpServletRequest 中,而后在以后申请中始终传递。三个办法如下: (1) preHandle(WebRequest request) :WebRequestInterceptor的该办法返回值为void,不是boolean。所以该办法不能用于申请阻断,个别用于资源筹备。 (2) postHandle(WebRequest request, ModelMap model):preHandle 中筹备的数据都能够通过参数WebRequest拜访。ModelMap 是Controller 解决之后返回的Model 对象,能够通过扭转它的属性来扭转Model 对象模型,达到扭转视图渲染成果的目标。 (3) afterCompletion(WebRequest request, Exception ex) :。Exception 参数示意的是以后申请的异样对象,如果Controller 抛出的异样曾经被解决过,则Exception对象为null 。 单个拦截器的执行流程运行程序时,拦截器的执行时有肯定程序的,该程序与配置文件中所定义的拦挡的程序相干。如果程序中只定义了一个拦截器,则该单个拦截器在程序中的执行流程如图所示。 程序首先执行拦截器类中的preHandle()办法,如果该办法返回值是true,则程序会持续向下执行处理器中的办法,否则不再向下执行;在业务控制器类Controller解决完申请后,会执行postHandle()办法,而后会通过DispatcherServlet向客户端返回相应;在DispatcherServlet解决完申请后,才会执行afterCompletion()办法。 单个拦截器的执行流程 上面在springmvc-6的我的项目中通过示例来演示单个拦截器的执行流程,步骤如下: (1) 在src目录下的com.springmvc.controller包中的UserController类中,新建一个hello()办法,并应用@RequestMapping注解进行映射。 package com.springmvc.controller;import java.util.Locale;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.context.i18n.LocaleContextHolder;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.validation.annotation.Validated;import org.springframework.web.bind.annotation.ModelAttribute;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.servlet.i18n.CookieLocaleResolver;import org.springframework.web.servlet.i18n.SessionLocaleResolver;import org.springframework.web.servlet.support.RequestContext;import com.springmvc.entity.User;@Controllerpublic class UserController { @RequestMapping("/hello") public String hello() { System.out.println("Hello!Controller控制器类执行hello办法"); return "hello"; }}(2) 在src目录下,新建一个com.springmvc.interceptor包,创立拦截器类MyInterceptor,实现HandlerInterceptor接口。 ...

September 15, 2020 · 3 min · jiezi

关于spring:Spring是如何解决的循环依赖

Spring解决循环依赖是有前置条件的: 呈现循环依赖的Bean必须要是单例依赖注入的形式不能全是结构器注入的形式依赖状况依赖注入形式循环依赖是否被解决AB相互依赖(循环依赖)均采纳setter办法注入是AB相互依赖(循环依赖)均采纳结构器注入否AB相互依赖(循环依赖)A中注入B的形式为setter办法,B中注入A的形式为结构器是AB相互依赖(循环依赖)B中注入A的形式为setter办法,A中注入B的形式为结构器否创立A的过程实际上就是调用getBean办法,这个办法有两层含意 创立一个新的Bean从缓存中获取到曾经被创立的对象???? Spring通过三级缓存解决了循环依赖,其中一级缓存为单例池(singletonObjects),二级缓存为晚期曝光对象(earlySingletonObjects),三级缓存为晚期曝光对象工厂(singletonFactories)。 getSingleton(beanName, true)这个办法实际上就是到缓存中尝试去获取Bean,整个缓存分为三级 singletonObjects,一级缓存,存储的是所有曾经齐全创立好了的单例BeanearlySingletonObjects,实现实例化,然而还未进行属性注入及初始化的对象singletonFactories,提前裸露的一个单例工厂,二级缓存中存储的就是从这个工厂中获取到的对象当A、B两个类产生循环援用时,在A实现实例化后,就应用实例化后的对象去创立一个对象工厂,并增加到三级缓存中,如果A被AOP代理,那么通过这个工厂获取到的就是A代理后的对象,如果A没有被AOP代理,那么这个工厂获取到的就是A实例化的对象。 当A进行属性注入时,会去创立B,同时B又依赖了A,所以创立B的同时又会去调用getBean(a)来获取须要的依赖,此时的getBean(a)会从缓存中获取:第一步,先获取到三级缓存中的工厂;第二步,调用对象工工厂的getObject办法来获取到对应的对象,失去这个对象后将其注入到B中。紧接着B会走完它的生命周期流程,包含初始化、后置处理器等。 当B创立完后,会将B再注入到A中,此时A再实现它的整个生命周期。至此,循环依赖完结! 面试官:”为什么要应用三级缓存呢?二级缓存能解决循环依赖吗?“答:如果要应用二级缓存解决循环依赖,意味着所有Bean在实例化后就要实现AOP代理,这样违反了Spring设计的准则,Spring在设计之初就是通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来在Bean生命周期的最初一步来实现AOP代理,而不是在实例化后就立马进行AOP代理。 转载:讲一讲Spring中的循环依赖

September 15, 2020 · 1 min · jiezi

关于spring:开源项目跨项目及操作系统的通用代码生成器解放您的双手

一、设计主旨所有被程序员把握了代码法则的常识,都能够用代码生成器实现开发 模板类代码生成,加重程序员的开发工作量,这当然是外围需要。生成的代码间接利用于我的项目,能够指定代码的生成门路,间接让代码生成到我的项目门路上面。跨我的项目,很多的代码生成器都是基于某个作者本人的我的项目开发的。(你只须要学会模板的开发,这个代码生成器实用于所有的我的项目)。跨语言,不管你是python、vue,只有你的代码是模板化的,都能够实现主动生成。跨操作系统,采纳electron开发,所以能够打包装置到windows、linux、macOS都能够。本代码生成器的设计思路,和其余的代码生成器并没有什么非凡之处。依然是:数据 + 模板 = 文件。 其实模板的编写是小事件,个别的开发人员十分钟就学会了。重要的是了解这些数据都能用来做什么,了解了这些数据能做什么之后,你就能编写本人的模板,实用于本人的我的项目。 二、下载与装置下载我的项目gitee源码地址(安装文件下载地址):https://gitee.com/hanxt/dongb... 点击"发行版"Tab 下载安装版本(目前手头只有windows,所以只打了windows的包)。应用linux或macOS的小伙伴,能够下载源码,应用yarn electron:build命令自行打包。 装置这个装置就比较简单了 抉择装置目录 装置实现之后,桌面上会呈现这样一个图标,点击就能够启动代码生成器 初始数据导入代码生成器启动之后,DB配置、我的项目配置、模板配置等都是空的,须要使用者依据本人的我的项目状况自行配置。 问:能不能给一个配置的例子,咱们参考你配置实现的内容进行配置?。答 :https://gitee.com/hanxt/dongb... 这个配置文件下载到你的本地,保留文件名为data.json。 而后通过下图中的性能导入data.json这个文件就能够了。 我的这个data.json的配置就是针对dongbb我的项目的代码生成配置,如果你是应用dongbb我的项目,这个配置简直就能够拿来即用了(模板文件门路和代码生成门路须要批改)。 如果你用于其余的我的项目,还须要自行配置,具体怎么配置。参看后文的应用办法介绍。 三、应用办法新建表代码生成器的外围原理就是依据这张表的信息(当然还有其余的配置信息),来生成针对这张表的增删改查性能及页面。 字段的程序,默认是在前端页面的table(tr/td)的数据从左到右的展现程序字段的名称要合乎下划线宰割的数据库字段根本标准带有长度的字段(字符串类型),能够用来生成前端数据校验的最大值校验规定是否容许为null的字段,能够用来生成前端数据校验的必填项校验规定表的正文信息,和字段的正文信息,能够用来生成代码文件中的正文信息。减少数据库配置减少数据库配置的作用是,将在数据库外面新建的表信息查问进去,用来生成代码文件。为了齐全起见,本软件并不保留您的数据库明码信息,须要每次生成代码的时候再填写。 欠缺字段配置信息当咱们新增一条DB配置之后,表格外面会多出一条数据库信息记录。 点击图中红色框地位,输出数据库明码,会弹出一个框,框外面蕴含该数据库外面的所有的表信息。 咱们抉择咱们刚刚新建的一张表:affice_goods(为了不便测试,成心以a结尾,不便查找),进行配置代码生成信息。 红色,是否前端table查问参数,示意该字段是否作为table数据的查问条件。代码生成之后,勾选的字段将作为查问条件存在。(下图是代码生成之后前端展现成果) 绿色,是否在前端的table中显示,示意该字段是否作为前端table的数据展现内容呈现。代码生成之后,勾选的字段将作为table数据展现列存在。(下图是代码生成之后前端展现成果) 橘色,是都在前端新增批改,示意该字段是否在前端能够新增批改。比方:id,create_time个别是由后端主动赋值的,不禁用户来填写,这里就不要勾选。(下图是代码生成之后前端展现成果) 我的项目配置我的项目配置临时没有特地的作用,通常只用于模板分类,示意哪一个模板属于拿一个我的项目(模板配置看下文)。 模板配置模板配置中的每一个模板,对应代码生成之后的每一个代码文件(vue、js、java等)。只有你能总结出代码法则,并把它编写成模板,所有的代码都能够生成。 模板文件的编写非常简单,后续我会录制一段视频给大家讲一下,文档也会有!新增或批改模板 生成代码 开源地址https://gitee.com/hanxt/dongb...如果您感觉这个代码生成器可能帮忙到你,请帮忙给个star。 期待您关注我的博客,外面有很多我的技术常识精品合集本文转载注明原始出处: 字母哥博客 - zimug.com

September 15, 2020 · 1 min · jiezi

关于spring:Spring-5-中文解析测试篇WebTestClient

3.7 WebTestClientWebTestClient是围绕WebClient的薄壳,可用于执行申请并公开专用的流畅API来验证响应。 WebTestClient通过应用模仿申请和响应绑定到WebFlux应用程序,或者它能够通过HTTP连贯测试任何Web服务器。 Kotlin用户:请参阅本节与WebTestClient的应用无关。3.7.1 装置要创立WebTestClient,必须抉择多个服务器设置选项之一。实际上,你是在配置WebFlux应用程序以绑定到该URL,还是应用URL连贯到正在运行的服务器。 绑定到控制器 以下示例显示如何创立服务器设置以一次测试一个@Controller: client = WebTestClient.bindToController(new TestController()).build();后面的示例加载WebFlux Java配置并注册给定的控制器。应用模仿申请和响应对象,能够在没有HTTP服务器的状况下测试生成的WebFlux应用程序。构建器上有更多办法能够定制默认WebFlux Java配置。 绑定到路由器性能 以下示例显示了如何通过RouterFunction设置服务器: RouterFunction<?> route = ...client = WebTestClient.bindToRouterFunction(route).build();在外部,配置被传递到RouterFunctions.toWebHandler。应用模仿申请和响应对象,能够在没有HTTP服务器的状况下测试生成的WebFlux应用程序。 绑定到ApplicationContext 以下示例显示了如何通过应用程序或其局部子集的Spring配置来设置服务器: @SpringJUnitConfig(WebConfig.class) //1class MyTests { WebTestClient client; @BeforeEach void setUp(ApplicationContext context) { //2 client = WebTestClient.bindToApplicationContext(context).build(); //3 }}指定要加载的配置注入配置创立WebTestClient在外部,配置被传递到WebHttpHandlerBuilder以建设申请解决链。无关更多详细信息,请参见WebHandler API。应用模仿申请和响应对象,能够在没有HTTP服务器的状况下测试生成的WebFlux应用程序。 绑定到服务器 以下服务器设置选项使你能够连贯到正在运行的服务器: client = WebTestClient.bindToServer().baseUrl("http://localhost:8080").build();客户端构建者 除了后面介绍的服务器设置选项之外,你还能够配置客户端选项、包含根本URL、默认标头,客户端过滤器等。这些选项在bindToServer之后很容易取得。对于所有其余服务器,你须要应用configureClient()从服务器配置过渡到客户端配置,如下所示: client = WebTestClient.bindToController(new TestController()) .configureClient() .baseUrl("/test") .build();3.7.2 写测试WebTestClient提供了与WebClient雷同的API,直到应用exchange()执行申请为止。 exchange()之后是链接的API工作流,用于验证响应。 通常,首先申明响应状态和标头,如下所示: client.get().uri("/persons/1") .accept(MediaType.APPLICATION_JSON) .exchange() .expectStatus().isOk() .expectHeader().contentType(MediaType.APPLICATION_JSON)而后,你指定如何解码和应用响应主体: ExpectBody(Class <T>):解码为单个对象。ExpectBodyList(Class <T>):解码并将对象收集到List <T>。ExpectBody():解码为byte []以获取JSON内容或一个空的注释。而后,你能够为主体应用内置的断言。以下示例显示了一种办法: ...

September 14, 2020 · 1 min · jiezi

关于spring:面试前看了这篇spring事务的文章让我多要了2k的工资

继上一篇《spring事务的这10种坑,你稍不留神可能就会踩中!!!》之后,我打算对spring的事务做详细分析,带大家一起探讨一下spring事务的设计原理和底层实现,心愿这篇文章可能让你有所播种。 一、开启事务性能1、spring开启事务 有些敌人的公司可能还没有应用springboot,这里我介绍一下spring的事务开启。当然,我次要介绍的是基于注解的形式配置spring事务,因为基于xml的形式相对来说有些繁琐,并且比拟古老,我在这里就不做赘述了。 基于注解的办法应用起来非常简单,使@EnableTransactionManagement 注解就能够开启事务性能。 @Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Import(TransactionManagementConfigurationSelector.class)public @interface EnableTransactionManagement { /** * true:cglib代理 false:jdk动静代理 */ boolean proxyTargetClass() default false; /** * PROXY:代理的告诉模式 ASPECTJ:ASPECTJ的告诉模式 */ AdviceMode mode() default AdviceMode.PROXY; /** * 如果存在多个切换时能够指定执行程序 */ int order() default Ordered.LOWEST_PRECEDENCE;}接下来重点看一下TransactionManagementConfigurationSelector 类 public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> { @Override protected String[] selectImports(AdviceMode adviceMode) { switch (adviceMode) { case PROXY: return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()}; case ASPECTJ: return new String[] { TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME}; default: return null; } }}该办法逻辑比较简单,就是判断告诉模式是 PROXY,还是ASPECTJ。咱们重点介绍的是 PROXY模式,如果对ASPECTJ模式感兴趣的敌人,能够深入研究一下。 ...

September 14, 2020 · 15 min · jiezi

关于spring:一起来读官方文档SpringIOC04

1.4.2。依赖性和具体配置如上一节所述,您能够将bean属性和结构函数参数定义为对其余托管bean(协作者)的援用或内联定义的值。Spring的基于XML的配置元数据为此目标在其<property/>和<constructor-arg/>元素中反对子元素类型。 直值(原语,字符串等)在value所述的属性<property/>元素指定属性或结构器参数的人类可读的字符串示意。Spring的 转换服务用于将这些值从转换String为属性或参数的理论类型。以下示例显示了设置的各种值: <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <!-- results in a setDriverClassName(String) call --> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mydb"/> <property name="username" value="root"/> <property name="password" value="misterkaoli"/></bean><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="com.mysql.jdbc.Driver" p:url="jdbc:mysql://localhost:3306/mydb" p:username="root" p:password="misterkaoli"/></beans>后面的XML更简洁。然而,拼写错误是在运行时而不是设计时发现的,除非您应用IDE(例如IntelliJ IDEA或用于Eclipse的Spring工具)在创立bean定义时反对主动属性实现。 您还能够配置java.util.Properties实例,如下所示: <bean id="mappings" class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"> <property name="properties"> <value> jdbc.driver.className=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mydb </value> </property></bean>Spring容器将<value></value>元素中的文本转换为java.util。属性实例,通过应用JavaBeans的PropertyEditor机制。这是一个很好的快捷方式,也是Spring团队偏爱应用嵌套的<value></value>元素而不是value属性款式的几个中央之一。 idref元素所述idref元件是一个防错办法,次要通过将该容器中的另一个bean的id(将id作为一个字符串值传递-而不是援用)传递给<constructor-arg/>或<property/>标签。 以下示例显示了如何应用它: <bean id="theTargetBean" class="..."/><bean id="theClientBean" class="..."> <property name="targetName"> //此处将 theTargetBean 作为字符串传递给 theClientBean的targetName属性 //而不是将theTargetName这个bean的实例传递给targetName属性 <idref bean="theTargetBean"/> </property></bean>后面的bean定义代码段(在运行时)与以下代码段齐全等效: idref 等价的是 value标签 而不是 ref标签 <bean id="theTargetBean" class="..." /><bean id="client" class="..."> <property name="targetName" value="theTargetBean"/></bean>元素 的local属性在idref4.0 Bean XSD中不再受反对,因为它不再提供惯例bean援用上的值。降级到4.0模式时,将现有idref local援用更改为idref bean。idref用法 能够校验传入的作为bean的id 会被用来校验以后id的bean存不存在 <idref></idref>元素罕用的地位(至多在spring2.0之前的版本中)是在ProxyFactoryBean bean定义中的AOP拦截器配置中。在指定拦截器名称时应用<idref></idref>元素能够避免拼写错误。ref 对其余Bean的援用ref元素是<constructor-arg>或</property>定义元素中的最初一个元素。在这里,您将bean的指定属性的值设置为对容器治理的另一个bean的援用。被援用的bean是要设置其属性的bean的依赖项,并且在设置属性之前依据须要初始化它(如果协作者是单例bean,它可能曾经被容器初始化了)。所有援用最终都是对另一个对象的援用。范畴和验证取决于是否通过bean或父属性指定其余对象的ID或名称。 通过<ref></ref>标记的bean属性指定指标bean是最通用的模式,它容许创立对同一容器或父容器中任何bean的援用,而不论它是否在同一XML文件中。bean属性的值能够与指标bean的id属性雷同,或者与指标bean的name属性中的一个值雷同。上面的例子展现了如何应用ref元素: //someBean 能够是bean的id 也能够是bean的name<ref bean="someBean"/>ref元素的local属性在ref4.0 Bean XSD中不再受反对, 因为它不再提供惯例bean援用上的值。降级到4.0模式时,将现有ref local援用更改ref bean为。 ...

September 14, 2020 · 5 min · jiezi

关于spring:Spring-5-中文解析测试篇Spring-MVC测试框架

3.6 Spring MVC测试框架Spring MVC测试框架提供了一流的反对,可应用可与JUnit、TestNG或任何其余测试框架一起应用的晦涩API测试Spring MVC代码。它基于spring-test模块的Servlet API模仿对象构建,因而不应用运行中的Servlet容器。它应用DispatcherServlet提供残缺的Spring MVC运行时行为,并反对通过TestContext框架加载理论的Spring配置以及独立模式,在独立模式下,你能够手动实例化控制器并一次对其进行测试。 Spring MVC Test还为应用RestTemplate的代码提供客户端反对。客户端测试模仿服务器响应,并且不应用正在运行的服务器。 Spring Boot提供了一个选项,能够编写包含运行中的服务器在内的残缺的端到端集成测试。如果这是你的指标,请参阅《 Spring Boot参考指南》。无关容器外和端到端集成测试之间的区别的更多信息,请参阅Spring MVC测试与端到端测试。3.6.1 服务端测试你能够应用JUnit或TestNG为Spring MVC控制器编写一个一般的单元测试。为此,实例化控制器,向其注入模仿或存根依赖性,而后调用其办法(依据须要传递MockHttpServletRequest,MockHttpServletResponse等)。然而,在编写这样的单元测试时,仍有许多未经测试的内容:例如,申请映射、数据绑定、类型转换、验证等等。此外,也能够在申请解决生命周期中调用其余控制器办法,例如@InitBinder、@ModelAttribute和@ExceptionHandler。 Spring MVC Test的指标是通过执行申请并通过理论的DispatcherServlet生成响应来提供一种测试控制器的无效办法。Spring MVC Test基于spring-test模块中可用的Servlet API的“模仿”实现。这容许执行申请和生成响应,而无需在Servlet容器中运行。在大多数状况下,所有都应像在运行时一样工作,但有一些值得注意的例外,如Spring MVC测试与端到端测试中所述。以下基于JUnit Jupiter的示例应用Spring MVC Test: import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.;import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.;@SpringJUnitWebConfig(locations = "test-servlet-context.xml")class ExampleTests { MockMvc mockMvc; @BeforeEach void setup(WebApplicationContext wac) { this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); } @Test void getAccount() throws Exception { this.mockMvc.perform(get("/accounts/1") .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().contentType("application/json")) .andExpect(jsonPath("$.name").value("Lee")); }}Kotlin提供了专用的MockMvc DSL后面的测试依赖于TestContext框架对WebApplicationContext的反对,以从与测试类位于同一包中的XML配置文件加载Spring配置,然而还反对基于Java和基于Groovy的配置。请参阅这些样本测试。 MockMvc实例用于执行对/accounts/1的GET申请,并验证后果响应的状态为200,内容类型为application/json,响应主体具备名为name的JSON属性,其值为Lee。Jayway JsonPath我的项目反对jsonPath语法。本文档前面将探讨用于验证执行申请后果的许多其余选项。 参考代码:org.liyong.test.annotation.test.spring.WebAppTests动态导入 上一节中的示例中的流式API须要一些动态导入,例如MockMvcRequestBuilders.*,MockMvcResultMatchers.* 和MockMvcBuilders.*。 查找这些类的一种简略办法是搜寻与MockMvc *相匹配的类型。如果你应用Eclipse或Spring Tools for Eclipse,请确保在Java→编辑器→Content Assist→Favorites下的Eclipse首选项中将它们增加为“favorite static members”。这样,你能够在键入静态方法名称的第一个字符后应用内容辅助。其余IDE(例如IntelliJ)可能不须要任何其余配置。查看对动态成员的代码实现反对。 ...

September 13, 2020 · 6 min · jiezi

关于spring:一起来读官方文档SpringIOC03

1.4。依存关系典型的企业应用程序不坑你只蕴含单个对象或单个bean。即便是最简略的应用程序,也有一些对象能够协同工作,以出现最终用户视为统一的应用程序。下一部分将阐明如何从定义多个独立的Bean定义到实现对象合作以实现目标的齐全实现的应用程序。 1.4.1。依赖注入依赖注入(Dependency injection,DI)是一个过程,对象通过结构函数参数、工厂办法的参数或在结构或从工厂办法返回后在对象实例上设置的属性来定义它们的依赖项(即与它们一起工作的其余对象)。 而后,容器在创立bean时注入这些依赖项。 这个过程基本上是bean自身的反向(因而得名,管制的反转),通过应用类的间接结构或服务定位器模式,bean本人管制其依赖项的实例化或地位。 应用DI准则,代码会更清晰,并且当向对象提供它们的依赖时,解耦会更无效。对象不查找其依赖项,也不晓得依赖项的地位或类。因而,您的类变得更容易测试,特地是当依赖关系在接口或形象基类上时,它们容许在单元测试中应用stub或mock实现。 依赖注入有两种次要的变体:基于结构器的依赖注入和基于setter的依赖注入。基于构造函数的依赖注入基于构造函数的DI是通过容器调用具备多个参数(每个参数代表一个依赖项)的构造函数来实现的。调用static带有特定参数的工厂办法来结构Bean简直是等效的,并且本次探讨将构造函数和static工厂办法的参数视为相似。以下示例显示了只能通过构造函数注入进行依赖项注入的类: public class SimpleMovieLister { // SimpleMovieLister 依赖项 MovieFinder private MovieFinder movieFinder; // 构造函数,以便Spring容器可能注入MovieFinder public SimpleMovieLister(MovieFinder movieFinder) { this.movieFinder = movieFinder; }}留神,该类没有什么特地的。它是一个POJO,不依赖于特定于容器的接口,基类或正文。 结构函数参数解析结构函数参数解析匹配通过应用参数的类型进行。如果Bean定义的结构函数参数中不存在潜在的歧义,则在实例化Bean时,在Bean定义中定义结构函数参数的程序就是将这些参数提供给适当的构造函数的程序。思考以下类别: package x.y;public class ThingOne { public ThingOne(ThingTwo thingTwo, ThingThree thingThree) { // ... }}假如ThingTwo和ThingThree类不是通过继承关联的,则不存在潜在的歧义。因而,以下配置能够失常工作,并且您无需在<constructor-arg/> 元素中显式指定结构函数参数索引或类型。 <beans> <bean id="beanOne" class="x.y.ThingOne"> <constructor-arg ref="beanTwo"/> <constructor-arg ref="beanThree"/> </bean> <bean id="beanTwo" class="x.y.ThingTwo"/> <bean id="beanThree" class="x.y.ThingThree"/></beans>当援用另一个bean时,类型是已知的,并且能够产生匹配(与后面的示例一样)。当应用简略的类型(例如)时 <value>true</value>,Spring无奈确定值的类型,因而在没有帮忙的状况下无奈按类型进行匹配。思考以下类别: package examples;public class ExampleBean { private int years; private String ultimateAnswer; public ExampleBean(int years, String ultimateAnswer) { this.years = years; this.ultimateAnswer = ultimateAnswer; }}结构函数参数类型匹配在上述情况下,如果通过应用type属性显式指定结构函数参数的类型,则容器能够应用简略类型的类型匹配。如下例所示: ...

September 13, 2020 · 2 min · jiezi

关于spring:图解并发与并行分别从CPU和线程的角度理解

本文作为图解java并发编程的第三篇,前2篇拜访地址如下所示: 图解过程线程、互斥锁与信号量-看完还不懂你来打我8成以上的java线程状态图都画错了--图解java并发第二篇一、CPU角度的并发与并行 并发已经我作为一个不是很爱学习的孩子,在上学的时候常常做这样的事件:在数学课上补物理作业,数学课听懂了,物理作业也上交了。不谦虚的说,我是具备这样的能力,但很惋惜没用对中央。 很多同学说:“你是不是有多个大脑?”,必定不是啊,其实这是一种切换的能力。当你同时做多件事件,并且可能疾速切换的时候。在他人开来,你就有了并发的能力,然而你的大脑还是一个大脑。 咱们的计算机在绝大部分工夫都运行很多很多的过程与线程,所以CPU并发执行并切换调配CPU工夫片资源是一种常态。只是CPU的执行速度切实是太快了,快到绝大部分状况下你都无奈感知“执行线程的切换”。所以看上去它在一边播放音乐,一边运行浏览器,一边运行其他软件。 并行晓得了计算机中并发的概念,咱们来举例理解一下并行的概念。 你在餐厅点餐,点餐后等餐的同时你在读书。看上去你是在做两件事,等餐和读书。实际上只有一件事是须要你实际操作的,那就是读书;另外一件事实际上是做菜,做菜是由餐厅的厨师进行的。随着计算机多核CPU的遍及,计算机也在肯定水平上具备了并行计算的能力。那这么说,单核心的CPU就肯定不存在并行能力喽?也并非齐全如此,若单核心的CPU领有Hyper-threading技术,那么单核心能够并行的运行两个逻辑线程。 二、线程角度的并发与并行下面的并发与并行的解释更多的是从CPU运行的角度,但作为程序员更关怀的是作为开发者如何辨别并发与并行。 从线程的角度去谈并行,通常是指在多线程间不存在数据共享或通信,可能利用CPU的并行能力去运行多线程。 从线程的角度去谈并发,通常是指多个线程之间存在资源共享(内存、代码段等),彼此协调共享资源的应用,从而交出或取得CPU执行工夫片的使用权。 总结一句话,心愿对你与了解并发与并行有帮忙,并发是看上去的并行,实际上的资源切换,并发目标是将资源利用能力最大化、最优化。 期待您关注我的博客,外面有很多我的技术常识精品合集本文转载注明原始出处: 字母哥博客 - zimug.com

September 13, 2020 · 1 min · jiezi

关于spring:Spring-Angular-前后端分离项目中的文件下载

前言近期在生产我的项目中遇到了文件上传与下载的问题,业务逻辑如下: Angular从Java服务器中获取Excel模板,供用户下载用户填写实现后,通过Angular上传至服务器。本文专一于探讨前后端拆散我的项目的文件下载的问题。 下载(Spring->Angular)用户从服务器上获取Excel模板 文件传输格局模板文件放在Spring我的项目的Resources文件夹中Spring应用File类型来发送文件Angular应用Blob类型来接管文件搁置文件在Recourses目录搁置待传输的文件,相似这样: 示例文件 /upload/老师上传模板.xlsx Spring Service此处有一个坑,在我的项目的其它代码中发现了上传文件应用的是MultipartFile类型,天经地义的工作下载文件也是MultipartFile类型。而后怎么使也不行,节约了好多工夫。最初才晓得MultipartFile和File的继承树齐全不同,尽管有方法互相转化,但基本不通用。UserService: /** * 用户模板下载 * * @return 模板文件 */File download();UserServiceImpl: /** * 用户模板下载 * * @return File类型 模板文件 */public File download() { // throw IOException 须要捕捉 try { // 获取文件 File file = new ClassPathResource("upload/老师上传模板.xlsx").getFile(); // 返回文件 return (file); } catch (Exception e) { // 打印信息,返回null logger.debug("模板下载失败"); return null; }}须要留神的是 ClassPathResource("upload/老师上传模板.xlsx").getFile(); 中的门路以Resources为根目录。 Spring ControllerUserCortroller: @GetMapping("download")public File downloadTemplate() { return this.userService.download();}至尔后端编写结束,提供接口 user/download ...

September 12, 2020 · 1 min · jiezi

关于spring:Spring-Security-权限管理的投票器与表决机制

明天咱们来聊一聊 Spring Security 中的表决机制与投票器。 当用户想拜访 Spring Security 中一个受爱护的资源时,用户具备一些角色,该资源的拜访也须要一些角色,在比对用户具备的角色和资源须要的角色时,就会用到投票器和表决机制。 当用户想要拜访某一个资源时,投票器依据用户的角色投出赞成或者反对票,表决形式则依据投票器的后果进行表决。 在 Spring Security 中,默认提供了三种表决机制,当然,咱们也能够不必零碎提供的表决机制和投票器,而是齐全本人来定义,这也是能够的。 本文松哥将和大家重点介绍三种表决机制和默认的投票器。 1.投票器先来看投票器。 在 Spring Security 中,投票器是由 AccessDecisionVoter 接口来标准的,咱们来看下 AccessDecisionVoter 接口的实现: 能够看到,投票器的实现有好多种,咱们能够抉择其中一种或多种投票器,也能够自定义投票器,默认的投票器是 WebExpressionVoter。 咱们来看 AccessDecisionVoter 的定义: public interface AccessDecisionVoter<S> { int ACCESS_GRANTED = 1; int ACCESS_ABSTAIN = 0; int ACCESS_DENIED = -1; boolean supports(ConfigAttribute attribute); boolean supports(Class<?> clazz); int vote(Authentication authentication, S object, Collection<ConfigAttribute> attributes);}我略微解释下: 首先一上来定义了三个常量,从常量名字中就能够看出每个常量的含意,1 示意赞成;0 示意弃权;-1 示意回绝。两个 supports 办法用来判断投票器是否反对以后申请。vote 则是具体的投票办法。在不同的实现类中实现。三个参数,authentication 示意以后登录主体;object 是一个 ilterInvocation,里边封装了以后申请;attributes 示意以后所拜访的接口所须要的角色汇合。咱们来别离看下几个投票器的实现。 ...

September 12, 2020 · 3 min · jiezi

关于spring:java版电子商务spring-cloud分布式微服务b2b2c社交电商

核心思想:分布式、微服务、云架构、模块化、原子化、继续集成、集群部署 外围架构:Spring Cloud、Spring Boot、Mybatis Plus、Redis 开发模式:代码生成工具、驱动式开发模式、进步开发效率 社交模式:VR全景虚拟现实、直播带货、短视频带货、分销分润、代跑腿配送等 JDK/数据库:JDK 1.8+/MYSQL 5.6+前端框架:VUE、小程序 波及平台:平台治理(蕴含自营店面)、商家端(PC端、手机端)、买家平台(小程序)、微服务

September 11, 2020 · 1 min · jiezi

关于spring:一起来读官方文档SpringIOC02

1.3。Bean总览Spring IoC容器治理一个或多个bean。这些bean是应用您提供给容器的配置元数据创立的(例如,以XML <bean/>定义的模式 )。 在容器自身内,这些bean定义示意为BeanDefinition对象,其中蕴含(除其余信息外)以下元数据: 包限定的类名:通常,定义了Bean的理论实现类。 Bean行为配置元素,用于申明Bean在容器中的行为(作用域,生命周期回调等)。 援用其余bean进行其工作所需的bean。这些援用也称为协作者或依赖项。 要在新创建的对象中设置的其余配置设置-例如,池的大小限度或在治理连接池的Bean中应用的连接数。 该元数据转换为形成每个bean定义的一组属性。下表形容了这些属性: 属性解释类实例化bean名称bean名称生命周期bean生命周期结构函数参数依赖注入属性依赖注入主动注入模式主动注入的合作者提早初始化模式懒初始化bean初始化办法初始化回调销毁形式销毁回调除了蕴含无关如何创立特定bean的信息的bean定义外,这些ApplicationContext实现还容许注册在容器内部(由用户)创立的现有对象。这是通过办法拜访ApplicationContext的BeanFactory的getBeanFactory()来实现,该办法返回BeanFactory的DefaultListableBeanFactory实现。DefaultListableBeanFactory 通过registerSingleton(..)和 registerBeanDefinition(..)办法反对此注册。然而,典型的应用程序仅应用通过惯例bean定义元数据定义的bean。 自定义类 不带任何注解 public class LearnBean { public LearnBean(String name) { } public String getString(){ return "learnSpring"; } } 第一种:AnnotationConfigApplicationContext自带的registerBean办法,能够传入class和结构参数 AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(); annotationConfigApplicationContext.registerBean(LearnBean.class,""); annotationConfigApplicationContext.refresh(); LearnBean bean = (LearnBean) annotationConfigApplicationContext.getBean("learnBean"); System.out.println(bean.getString()); 第二种:还能够传入 class和beanDefinition也就是配置元数据 这个和 getBeanFactory().registerBeanDefinition(..)是一个意思 AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(); RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(LearnBean.class); ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues(); constructorArgumentValues.addIndexedArgumentValue(0,"111"); rootBeanDefinition.setConstructorArgumentValues(constructorArgumentValues); annotationConfigApplicationContext.registerBeanDefinition("learnBean",rootBeanDefinition); annotationConfigApplicationContext.refresh(); LearnBean bean = (LearnBean) annotationConfigApplicationContext.getBean("learnBean"); System.out.println(bean.getString()); 留神:如果不写 annotationConfigApplicationContext.refresh();就会报错Exception in thread "main" java.lang.IllegalStateException: org.springframework.context.annotation.AnnotationConfigApplicationContext@68de145 has not been refreshed yet at org.springframework.context.support.AbstractApplicationContext.assertBeanFactoryActive(AbstractApplicationContext.java:1096) at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1108) at org.springframework.example.DebuggerSpringMain.main(DebuggerSpringMain.java:40) Bean元数据和手动提供的单例实例须要尽早注册,以便容器在主动拆卸和其余自省步骤中正确地推理它们。尽管在某种程度上反对笼罩现有元数据和现有单例实例,然而在运行时(与对工厂的实时拜访同时)对新bean的注册不被正式反对,并且可能导致并发拜访异样,bean容器中的状态不统一或都。 ...

September 11, 2020 · 2 min · jiezi

关于spring:SpringBoot-WebFlux-系列-header-参数解析

【SpringBoot WebFlux 系列】WebFlux 之 header 参数解析上一篇 weblfux 次要介绍了 path 参数的解析与映射关系,在咱们进入 url 参数/post 表单之前,先看一下另外的一种参数--申请头中的参数如何解决 <!-- more --> I. 我的项目环境本我的项目借助SpringBoot 2.2.1.RELEASE + maven 3.5.3 + IDEA进行开发 1. 依赖应用 WebFlux,最次要的引入依赖如下(省略掉了 SpringBoot 的相干依赖,如对于如何创立 SpringBoot 我的项目不太分明的小伙伴,能够关注一下我之前的博文) <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency></dependencies>II. 申请头参数解析在理论的业务开发中,有几个申请头呈现的频率特地高,如常用于反爬的User-Agent,鉴定强求起源的referer,跨域相干的Access-Control-Allow-,cookie、session 自定义的申请头等 1. 申请头限度在RequestMapping或GetMapping中指定申请头参数时,示意只有申请中蕴含这个申请头才会匹配过来 /** * 只有申请头蕴含 myheader 且值为 myvalue的才能够拜访到 * * - 失常拜访: curl 'http://127.0.0.1:8080/header/filter/yihhui' -H 'myheader: myvalue' * - 异样拜访: curl 'http://127.0.0.1:8080/header/filter/yihhui' -H 'myheader: myvalue2' 因为申请头不匹配,404 * * @param name * @return */@GetMapping(path = "/filter/{name}", headers = "myheader=myvalue")public Mono<String> headerFilter(@PathVariable(name = "name") String name) { return Mono.just("request filter: " + name);}实例如下: ...

September 11, 2020 · 2 min · jiezi

关于spring:Spring-Value-设置默认值

1.概览Spring 的 @Vaule 注解提供了一种便捷的办法能够让属性值注入到组件中,当属性值不存在的时候提供一个默认值也是十分好用的 这就是咱们这篇文章所专一的,如何给 @Vaule 注解指定一个默认值。对于更多的对于 @Vaule 的教程看这篇文章 2.String 默认值让咱们看看对于 String 类型的值,给定一个默认值得根底语法 @Value("${some.key:my default value}")private String stringWithDefaultValue;如果 some.key 无奈解析,那么 stringWithDefaultValue 的值会被设置为默认值 "my default value". 类似的,咱们也能够用如下办法,设置一个空字符串作为默认值 @Value("${some.key:})"private String stringWithBlankDefaultValue;3.原始类型给像 int 或者 boolean 的原始类型赋一个默认值,咱们应用文字值: @Value("${some.key:true}")private boolean booleanWithDefaultValue;@Value("${some.key:42}")private int intWithDefaultValue;如果违心,能够用原始类型的包装类型来代替,例如 Boolean 和 Integer 4.数组咱们能够应用逗号分隔的 list 来用于数组的注入,如下 @Value("${some.key:one,two,three}")private String[] stringArrayWithDefaults; @Value("${some.key:1,2,3}")private int[] intArrayWithDefaults;在下面第一个例子, 值为 "one", "two", 和 "three" 的数组将被注入到 stringArrayWithDefaults 中 在下面第二个例子, 值为 1, 2, 和 3 的数组将被注入 intArrayWithDefaults 中 5.应用SpEL表达式咱们也能够应用 Spring Expression Language (SpEL) 去指定一个表达式或者默认值 ...

September 10, 2020 · 1 min · jiezi

关于spring:Spring-5-中文解析核心篇集成测试之TestContext中

3.5.5 上下文治理每个TestContext为其负责的测试实例提供上下文治理和缓存反对。测试实例不会主动接管对配置的ApplicationContext的拜访。然而,如果测试类实现ApplicationContextAware接口,则将对ApplicationContext的援用提供给测试实例。请留神,AbstractJUnit4SpringContextTests和AbstractTestNGSpringContextTests实现了ApplicationContextAware,因而能够主动提供对ApplicationContext的拜访。 @Autowired ApplicationContext 作为实现ApplicationContextAware接口的代替办法,你能够通过字段或setter办法上的@Autowired注解为测试类注入应用程序上下文,如以下示例所示: @SpringJUnitConfigclass MyTest { @Autowired //1 ApplicationContext applicationContext; // class body...}注入ApplicationContext。同样,如果将测试配置为加载WebApplicationContext,则能够将Web应用程序上下文注入到测试中,如下所示: @SpringJUnitWebConfig //1class MyWebAppTest { @Autowired //2 WebApplicationContext wac; // class body...}配置WebApplicationContext注入WebApplicationContext应用@Autowired的依赖关系注入是DependencyInjectionTestExecutionListener提供的,它是默认配置的(参见测试安装的依赖注入)。 应用TestContext框架的测试类不须要扩大任何特定的类或实现特定的接口来配置其应用程序上下文。而是通过在类级别申明@ContextConfiguration注解来实现配置。如果你的测试类未明确申明应用程序上下文资源地位或组件类,则配置的ContextLoader将确定如何从默认地位或默认配置类加载上下文。除了上下文资源地位和组件类之外,还能够通过应用程序上下文初始化程序配置应用程序上下文。 以下各节阐明如何应用Spring的@ContextConfiguration注解通过XML配置文件、Groovy脚本、组件类(通常为@Configuration类)或上下文初始化器来配置测试ApplicationContext。另外,你能够为高级用例实现和配置本人的自定义SmartContextLoader。 通过XML资源配置上下文通过Groovy脚本配置上下文通过组件类配置上下文XML、Groovy脚本、组件类混合通过上下文初始化器配置上下文上下文配置继承通过环境配置配置上下文通过测试属性源配置上下文通过动静属性源配置上下文加载 WebApplicationContext上下文缓存上下文层级通过XML资源配置上下文 若要应用XML配置文件为测试加载ApplicationContext,请应用@ContextConfiguration注解测试类,并应用蕴含XML配置元数据的资源地位的数组配置locations属性。简略门路或相对路径(例如context.xml)被视为绝对于定义测试类的程序包的类门路资源。以斜杠结尾的门路被视为相对类门路地位(例如:/org/example/config.xml)。照原样应用示意资源URL的门路(即以classpath:、file:、http:等结尾的门路)。 @ExtendWith(SpringExtension.class)// ApplicationContext从根门路加载"/app-config.xml" 和// "/test-config.xml"@ContextConfiguration(locations={"/app-config.xml", "/test-config.xml"}) //1class MyTest { // class body...}将locations属性设置为XML文件列表。@ContextConfiguration通过规范Java值属性为locations属性反对别名。因而,如果不须要在@ContextConfiguration中申明其余属性,你能够应用以下示例中演示的格局,省略locations属性名称的申明并申明资源地位。 @ExtendWith(SpringExtension.class)@ContextConfiguration({"/app-config.xml", "/test-config.xml"}) //1class MyTest { // class body...}不应用location属性指定XML文件。如果你从@ContextConfiguration注解中省略了地位和值属性,则TestContext框架将尝试检测默认的XML资源地位。具体而言,GenericXmlContextLoader和GenericXmlWebContextLoader依据测试类的名称检测默认地位。如果你的类名为com.example.MyTest则GenericXmlContextLoader将classpath:com/example/MyTest-context.xml加载应用程序上下文。以下示例显示了如何执行此操作: @ExtendWith(SpringExtension.class)// ApplicationContext will be loaded from// "classpath:com/example/MyTest-context.xml"@ContextConfiguration //1class MyTest { // class body...}从默认地位加载配置。通过Groovy脚本配置上下文 要通过应用Groovy Bean定义DSL的Groovy脚本为测试加载ApplicationContext,能够应用@ContextConfiguration注解测试类,并应用蕴含Groovy脚本资源地位的数组配置location或value属性。Groovy脚本的资源查找语义与针对XML配置文件形容的语义雷同。 激活Groovy脚本反对如果类门路中有Groovy,那么就会主动启用应用Groovy脚本在Spring TestContext框架中加载ApplicationContext的反对。 ...

September 9, 2020 · 5 min · jiezi

关于spring:一个Main方法的执行过程

一个简略的Main办法 public class Mm { public static void main(String[] args){ Mm mm = new Mm(); System.out.println(mm.getClass().getClassLoader()); }}javac Mm.java java Mm这么的话 就进行了一次编译并执行然而如上执行的话咱们是没方法调试的, 因而java Mm命令不要间接执行,用gdb模式执行 所以咱们要先编译一版openJDK,具体编译OpenJdk代码过程自行百度,举荐用Windows商店的ubuntu零碎编译 以下是OpenJdk源码,fork他人的 https://github.com/zscchaofan/openjdk-jdk8ugdb -q java Mm //gdb 设置 java 命令set args Mm //设置参数名 具体含意不懂百度搜的start //启动调试下边是设置的一些断点 都是一个一个试出来的 gdb 能够间接指定文件和行数打断点具体命令能够百度 我也是百度的就不总结了 也不罕用调试代码如果不参考他人的教程 那就得一步步的走 走几步就用gdb 命令查看一下以后代码高低左近的几行代码 再对应到源码下来看看像我这不懂c++语言的 只能一步步走 看到办法名用意很显著得中央再认真看3 breakpoint keep y 0x00007fffff1e7f4a in JavaMain at /mnt/d/code/openjdk-jdk8u-master/jdk/src/share/bin/java.c:4784 breakpoint keep y 0x00007ffffc97da55 in Java_java_lang_ClassLoader_findBootstrapClass at /mnt/d/code/openjdk-jdk8u-master/jdk/src/share/native/java/lang/ClassLoader.c:2659 breakpoint keep y 0x00007fffff1e9c72 in GetLauncherHelperClass at /mnt/d/code/openjdk-jdk8u-master/jdk/src/share/bin/java.c:1250 breakpoint already hit 1 time14 breakpoint keep y 0x00007ffffc97da94 in Java_java_lang_ClassLoader_findBootstrapClass at /mnt/d/code/openjdk-jdk8u-master/jdk/src/share/native/java/lang/ClassLoader.c:27215 breakpoint keep y 0x00007ffffc97d3ea in Java_java_lang_ClassLoader_defineClass1 at /mnt/d/code/openjdk-jdk8u-master/jdk/src/share/native/java/lang/ClassLoader.c:107/mnt/d/code/openjdk-jdk8u-master 是我寄存代码的门路其实是d盘code下,在ubuntu下加了/mnt 启动调试后gdb进入这里会主动停下,这就是最开始的中央 /mnt/d/code/openjdk-jdk8u-master/jdk/src/share/bin/main.c ...

September 9, 2020 · 2 min · jiezi

关于spring:Spring-学习笔记三Spring-Bean

1 Bean配置Spring能够看做是一个治理Bean的工厂,开发者须要将Bean配置在XML或者Properties配置文件中。理论开发中常应用XML的格局,其中<bean>中的属性或子元素如下: id:Bean在BeanFactory中的惟一标识,在代码中通过BeanFactory获取Bean的实例时候须要以此作为索引class:Bean的具体实体类,应用包名+类名的模式指定scope:指定Bean实例的作用域<constructor-arg>:应用构造方法注入,指定构造方法的参数,index示意序号,ref指定对BeanFactory中其余Bean的援用关系,type指定参数类型,value指定参数常量值<property>:用于设置一个属性,示意应用setter注入,name指定属性的名字,value指定要注入的值,ref指定注入的某个Bean的id<list>:用于封装List或者数组类型的依赖注入<map>:封装Map类型的依赖注入<set>:封装Set类型的依赖注入<entry>:<map>的子元素,用于设置一个键值对2 Bean实例化Spring实例化Bean有三种形式: 构造方法实例化动态工厂实例化实例工厂实例化上面进行简略的演示。 2.1 构造方法实例化Spring能够调用Bean对应的类的无参构造方法进行实例化,比方: public class TestBean { public TestBean() { System.out.println("构造方法实例化"); }}配置文件如下: <bean id="testBean" class="TestBean"/>则会调用无参构造方法初始化。 其实就是只写一个<bean>就能够了,默认的话会调用无参构造方法初始化。 2.2 动态工厂实例化动态工厂实例化须要在工厂类中配置一个静态方法来创立Bean,并增加factory-method元素,首先创立工厂类: public class TestBeanFactory { private static final TestBean testBean = new TestBean(); public static TestBean getInstance() { return testBean; }}接着配置文件通过class指定该工厂类,通过factory-method指定获取实例的办法: <bean id="testBeanFactory" class="TestBeanFactory" factory-method="getInstance"/>这样就能够通过id获取了: TestBean test = (TestBean) context.getBean("testBeanFactory");2.3 实例工厂实例化实例工厂实例化与动态工厂实例化相似,不过是非静态方法,而后加上一个factory-bean元素,同样首先创立工厂类: public class TestBeanFactory { public TestBean getInstance() { return new TestBean(); }}在配置文件须要增加两个Bean,一个指定工厂类,一个指定应用哪一个工厂类以及应用工厂类的哪一个办法: <bean id="factory" class="TestBeanFactory" /> <!--指定工厂类--><bean id="testBeanFactory" factory-bean="factory" factory-method="getInstance" /> <!--指定工厂Bean以及哪一个工厂办法-->获取: ...

September 9, 2020 · 3 min · jiezi

关于spring:Spring-学习笔记二SpringIoC

1 IoC与DIIoC是Inversion of Control的简称,也就是管制反转。通常来说,创建对象须要调用者手动创立,也就是new XXX()的形式。当Spring框架呈现后,对象的实例不再由调用者创立,而是由Spring容器创立,这样控制权就由调用者转移到Spring容器,控制权产生了反转,这就是Spring的管制反转。从Spring容器来看,Spring容器负责将被依赖对象赋值给调用者的成员变量,相当于为调用者注入它所依赖的实例,这就是Spring的依赖注入(Dependency Injection,DI)。 一句话总结: IoC:控制权由调用者交由Spring容器,管制产生了反转DI:由Spring容器注入须要的值到对象中2 Spring IoC容器Spring中实现IoC的是Spring IoC容器,次要基于以下两个接口: BeanFactoryApplicationContext2.1 BeanFactory位于org.springframework.beans.factory下,提供了残缺的IoC服务反对,是一个治理Bean工厂,次要负责初始化各种Bean。能够通过XmlBeanFactory来获取XML文件中的Bean并进行拆卸,例子如下: BeanFactory factory = new XmlBeanFactory(new FileSystemResource("/xxx/xxx/xxx/xxx/applicationContext.xml"));TestInterface test = (TestInterface)factory.getBean("test");test.hello();须要应用绝对路径,而且,该办法曾经过期了: 因而不举荐应用。 2.2 ApplicationContextApplicationContext是BeanFactory的子接口,也称为利用上下文,除了蕴含BeanFactory的性能外还增加了国际化、资源拜访、事件流传等的反对,创立ApplicationContext的实例有以下三种办法: ClassPathXmlApplicationContextFileSystemXmlApplicationContextWeb服务器实例化2.2.1 ClassPathXmlApplicationContext该类从resources下寻找指定的XML文件: ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");TestInterface test = (TestInterface)context.getBean("test");test.hello(); 2.2.2 FileSystemXmlApplicationContext该类读取配置文件须要加上前缀: classpath::该前缀示意从类门路读取,对于Maven我的项目来说就是resourcesfile::该前缀示意从绝对路径获取例子: ApplicationContext context = new FileSystemXmlApplicationContext("classpath:applicationContext.xml");//ApplicationContext context = new FileSystemXmlApplicationContext("file:/xxx/xxx/xxx/xxxx/xxx/applicationContext.xml");2.2.3 Web服务器实例化个别应用基于ContextLoaderListener的实现形式,批改web.xml,增加如下代码: <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener></context-param>3 DI的两种办法DI通常有两种实现形式: 构造方法注入setter注入上面别离来看一下。 3.1 构造方法注入Spring能够利用反射机制通过构造方法实现注入,比方有以下三个类: public interface TestInterface { void hello();}public class TestA implements TestInterface { @Override public void hello() { System.out.println("Test A"); }}public class TestB { private TestInterface test; public TestB(TestInterface test) { this.test = test; } public void method() { test.hello(); }}TestInterface是一个简略的接口,而TestA实现了该接口,TestB须要一个TestInterface类型的对象,因而能够先注入一个TestA,再将该TestA注入到TestB的构造方法中: ...

September 9, 2020 · 1 min · jiezi

关于spring:Spring-Boot基础

Spring 什么是Spring Boot?首先boot是‘疏导’的意思,就是说Spring Boot 是Spring的一个疏导程序。通过Spring Boot咱们能够更轻松地入门,更简略的应用Spring的框架。 为什么会有Spring Boot?随着利用的性能以及业务逻辑的日益简单,传统Spring程序往往随同着大量的XML配置文件以及简单的Bean依赖关系。Spring IO团队为了解脱Spring框架中各类简约纷杂的配置,应用“约定优于配置”的思维,在Spring根底上整合了大量罕用的第三方库的开发框架。Spring Boot就是在这种背景下诞生的。 Spring Boot的特点?内嵌式容器简化Web开发(咱们传统web程序大都跑在tomcat里,Spring Boot将tomcat集成在了应用程序中。)提供大量第三方库,不便援用(最次要的是解决了版本问题)提供性能衰弱状态监控(Actuator)提供各种默认配置来简化我的项目配置,没有冗余代码生成和XML配置的要求Spring Boot 的个性应用 Spring 我的项目疏导页面能够在几秒构建一个我的项目不便对外输入各种模式的服务,如 REST API、WebSocket、Web、Streaming、Tasks十分简洁的安全策略集成反对关系数据库和非关系数据库反对运行期内嵌容器,如 Tomcat、Jetty弱小的开发包,反对热启动主动治理依赖自带利用监控反对各种 IED,如 IntelliJ IDEA、NetBeans长处疾速的创立独立运行的spring利用,与支流的框架可能疾速的集成;无需配置xml,无代码生成,开箱即用;大量的主动配置,简化开发流程;应用嵌入式sevlet容器,能够通过 java -jar命令疾速启动利用;通过各种starts实现主动依赖和版本控制,比如说开发用到了spring mvc,spring boot会帮忙咱们导入spring mvc框架相干jar包以及jar包版本;Spring Boot 长处和个性独立运行Spring Boot而且内嵌了各种servlet容器,Tomcat、Jetty等,当初不再须要打成war包部署到容器中,Spring Boot只有打成一个可执行的jar包就能独立运行,所有的依赖包都在一个jar包内。 简化配置spring-boot-starter-web启动器主动依赖其余组件,简少了maven的配置。 主动配置Spring Boot能依据以后类门路下的类、jar包来主动配置bean,如增加一个spring-boot-starter-web启动器就能领有web的性能,无需其余配置。 无代码生成和XML配置Spring Boot配置过程中无代码生成,也无需XML配置文件就能实现所有配置工作,这一切都是借助于条件注解实现的,这也是Spring4.x的外围性能之一。 利用监控Spring Boot提供一系列端点能够监控服务及利用,做衰弱检测。

September 9, 2020 · 1 min · jiezi

关于spring:Spring基础

Spring 框架的构造Spring是一个轻量级管制反转(IoC)和面向切面(AOP)的容器框架 下图是Spring官网给出的Spring框架的结构图 从图中咱们能够看到Spring的四大局部:外围容器(container)、AOP模块、Web模块、Data模块。 首先看外围容器,从外围俩字咱们能够看出,这是Spring最重要的局部。次要的性能是实现了管制反转(IOC)与依赖注入(DI)、Bean配置、加载以及生命周期的治理。AOP模块:负责Spring的所有AOP(面向切面)的性能。Web模块:扩大了Spring的Web性能。使其合乎MVC的设计规范,最重要的是提供了Spring MVC的容器。Data模块:提供了一些数据相干的组件:包含JDBC、orm(对象关系映射)、事务操作、oxm(对象xml映射)、Jms(Java音讯服务)。各个模块介绍 spring core:提供了框架的根本组成部分,包含管制反转(Inversion of Control,IOC)和依赖注入(Dependency Injection,DI)性能。spring beans:提供了BeanFactory,是工厂模式的一个经典实现,Spring将治理对象称为Bean。spring context:构建于 core 封装包根底上的 context 封装包,提供了一种框架式的对象拜访办法。spring jdbc:提供了一个JDBC的形象层,打消了繁缛的JDBC编码和数据库厂商特有的错误代码解析, 用于简化JDBC。spring aop:提供了面向切面的编程实现,让你能够自定义拦截器、切点等。spring Web:提供了针对 Web 开发的集成个性,例如文件上传,利用 servlet listeners 进行 ioc 容器初始化和针对 Web 的 ApplicationContext。spring test:次要为测试提供反对的,反对应用JUnit或TestNG对Spring组件进行单元测试和集成测试。咱们能够看到Spring给咱们提供的模块相当的丰盛,无论是长久层、业务层还是管制层都有所波及。 Spring简直包揽除了业务逻辑之外的的所有工作,包含日志治理、事务管理、Bean治理、平安治理等。Spring致力于全套的Java问题的解决方案,在所有的Java能够涉足的畛域,Spring都会提供相应的反对。(即便没有反对,也会让咱们去整合)与第三方框架的整合。在我的了解中Spring框架就像一个插线板,而第三方框架就相当于插头,能够轻易地与它组合在一起。须要的时候就插上去,不须要的时候就拔掉,相当的不便。既然Spring如此的不便,那么它又是如何做到的呢? 很简略,通过两点: 管制反转(IOC)面向切面编程(AOP)为了升高Java开发的复杂性,Spring采取了以下4种要害策略 基于POJO的轻量级和最小侵入性编程;通过依赖注入和面向接口实现松耦合;基于切面和常规进行申明式编程;通过切面和模板缩小样板式代码。Spring 框架中都用到了哪些设计模式? 工厂模式:BeanFactory就是简略工厂模式的体现,用来创建对象的实例;单例模式:Bean默认为单例模式。代理模式:Spring的AOP性能用到了JDK的动静代理和CGLIB字节码生成技术;模板办法:用来解决代码反复的问题。比方. RestTemplate, JmsTemplate, JpaTemplate。观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态产生扭转时,所有依赖于它的对象都会失去告诉被制动更新,如Spring中listener的实现–ApplicationListener。应用 Spring 有哪些形式? 作为一个成熟的 Spring Web 应用程序。作为第三方 Web 框架,应用 Spring Frameworks 中间层。作为企业级 Java Bean,它能够包装现有的 POJO(Plain Old Java Objects)。用于近程应用。管制反转(IOC)/依赖注入(DI)既然说到管制反转,那么咱们不禁要问什么管制被反转了? 答案是:咱们对对象的控制权被反转了。咱们将对象的管制交给了Spring的容器。 那么问题又来了,什么是Spring的容器? 简略的说,Spring容器就是一个超级大工厂,负责创立、治理所有的Java对象,这些Java对象被称为Bean。Spring容器治理着容器中Bean之间的依赖关系,Spring应用一种被称为“依赖注入”的形式来治理Bean之间的依赖关系。 什么又是依赖注入呢? 依赖注入(DI)就是管制反转的一种实现模式,Spring容器也是通过这种模式治理Bean的。 Spring容器如何做到替你治理这些bean的呢? 工厂模式。 ...

September 9, 2020 · 1 min · jiezi

关于spring:Spring-5-中文解析核心篇集成测试之TestContext上

Spring TestContext 框架(位于org.springframework.test.context包中)提供了通用的、注解驱动的单元和集成测试反对,这些反对与所应用的测试框架无关。TestContext框架还非常重视约定优于配置,你能够通过基于注解的配置笼罩正当的默认值。 除了通用测试根底构造之外,TestContext框架还为JUnit 4,JUnit Jupiter(AKA JUnit 5)和TestNG提供了显式反对。对于JUnit 4和TestNG,Spring提供了形象反对类。此外,Spring为JUnit 4提供了自定义JUnit Runner和自定义JUnit规定,以及JUnit Jupiter的自定义扩大,可让你编写所谓的POJO测试类。不须要POJO测试类来扩大特定的类层次结构,例如形象反对类。下一节概述了TestContext框架的外部。如果你仅对应用框架感兴趣,而对应用本人的自定义监听器或自定义加载程序进行扩大不感兴趣,请间接转到配置(上下文治理 、依赖项注入、事务管理、反对类和注解反对局部。 3.5.1 要害形象该框架的外围由TestContextManager类和TestContext,TestExecutionListener和SmartContextLoader接口组成。为每个测试类创立一个TestContextManager(例如,用于在JUnit Jupiter中的单个测试类中执行所有测试方法)。反过来,TestContextManager治理蕴含以后测试上下文的TestContext。随着测试的进行,TestContextManager还更新了TestContext的状态,并委托给TestExecutionListener实现,该实现通过提供依赖项注入,治理事务等来检测理论的测试执行。SmartContextLoader负责为给定的测试类加载ApplicationContext。无关更多信息和各种实现的示例,请参见javadoc和Spring测试套件。 TestContext TestContext封装了在其中执行测试的上下文(与应用中的理论测试框架无关),并为其负责的测试实例提供了上下文治理和缓存反对。如果须要,TestContext还委托给SmartContextLoader来加载ApplicationContext。 TestContextManager TestContextManager是Spring TestContext 框架的次要入口点,并负责管理单个TestContext并在定义良好的测试执行点向每个注册的TestExecutionListener收回事件信号: 在任何before类之前或在特定测试框架的所有办法之前。测试实例后处理。在任何before或在每个特定测试框架的办法之前。在执行测试方法之前但在测试设置之后。在测试方法执行之后,但在测试装配之前。之后的任何办法或之后的每一个特定的测试框架。在特定测试框架的任何类后或所有办法之后。TestExecutionListener TestExecutionListener定义用于对由注册监听器的TestContextManager公布的测试执行事件做出反馈的API。请参阅TestExecutionListener配置。 上下文加载器 ContextLoader是一个策略接口,用于为Spring TestContext 框架治理的集成测试加载ApplicationContext。你应该实现SmartContextLoader而不是此接口,以提供对组件类,激活的bean定义配置文件、测试属性源、上下文层次结构和WebApplicationContext反对的反对。 SmartContextLoader是ContextLoader接口的扩大,它取代了原始的最小ContextLoader SPI。具体来说,SmartContextLoader能够抉择解决资源地位、组件类或上下文初始化器。此外,SmartContextLoader能够在其加载的上下文中设置激活Bean定义配置文件并测试属性源。 Spring提供了以下实现: DelegatingSmartContextLoader: 它是两个默认加载器之一,它在外部委派给AnnotationConfigContextLoader、GenericXmlContextLoader或GenericGroovyXmlContextLoader,具体取决于为测试类申明的配置或默认地位或默认配置类的存在。仅当Groovy在类门路上时才启用Groovy反对。WebDelegatingSmartContextLoader: 它是两个默认加载器之一,它在外部委派给AnnotationConfigWebContextLoader、GenericXmlWebContextLoader或GenericGroovyXmlWebContextLoader,具体取决于为测试类申明的配置或默认地位或默认配置类的存在。仅当测试类上存在@WebAppConfiguration时,才应用Web ContextLoader。仅当Groovy在类门路上时才启用Groovy反对。AnnotationConfigContextLoader:从组件类加载规范ApplicationContext。AnnotationConfigWebContextLoader: 从组件类加载WebApplicationContext。GenericGroovyXmlContextLoader: 从Groovy脚本或XML配置文件的资源地位加载规范ApplicationContext。GenericGroovyXmlWebContextLoader: 从Groovy脚本或XML配置文件的资源地位加载WebApplicationContext。GenericXmlContextLoader: 从XML资源地位加载规范ApplicationContext。GenericXmlWebContextLoader: 从XML资源地位加载WebApplicationContext。GenericPropertiesContextLoader:从Java属性文件加载规范ApplicationContext。3.5.2 疏导TestContext框架Spring TestContext 框架外部的默认配置足以满足所有常见用例。然而,有时开发团队或第三方框架心愿更改默认的ContextLoader,实现自定义的TestContext或ContextCache,扩大默认的ContextCustomizerFactory和TestExecutionListener实现等等。为了对TestContext框架的运行形式进行低级别管制,Spring提供了疏导策略。 TestContextBootstrapper定义了用于疏导TestContext框架的SPI。TestContextManager应用TestContextBootstrapper加载以后测试的TestExecutionListener实现并构建它治理的TestContext。你能够间接应用@BootstrapWith或作为元注解,为测试类(或测试类层次结构)配置自定义疏导策略。如果没有通过应用@BootstrapWith显式配置疏导程序,则依据@WebAppConfiguration的存在,应用DefaultTestContextBootstrapper或WebTestContextBootstrapper。 因为TestContextBootstrapper SPI未来可能会更改(以适应新的需要),咱们强烈建议实现者不要间接实现此接口,而应扩大AbstractTestContextBootstrapper或其具体子类之一。 3.5.3 TestExecutionListener配置Spring提供了以下TestExecutionListener实现,这些实现默认状况下按以下程序注册: ServletTestExecutionListener:为WebApplicationContext配置Servlet API模仿。DirtiesContextBeforeModesTestExecutionListener:解决before模式的@DirtiesContext注解。DependencyInjectionTestExecutionListener: 为测试实例提供依赖项注入。DirtiesContextTestExecutionListener: 解决after模式的@DirtiesContext注解。TransactionalTestExecutionListener: 提供具备默认回滚语义的事务测试执行。SqlScriptsTestExecutionListener: 运行应用@Sql正文配置的SQL脚本。EventPublishingTestExecutionListener: 将测试执行事件公布到测试的ApplicationContext中(请参阅测试执行事件)。注册TestExecutionListener实现 你能够应用@TestExecutionListeners注解为测试类及其子类注解TestExecutionListener实现。无关详细信息和示例,请参见注解反对和@TestExecutionListeners的javadoc。 默认TestExecutionListener实现主动发现 通过应用@TestExecutionListeners注册TestExecutionListener实现实用于无限测试计划中应用的自定义监听器。然而,如果须要在整个测试套件中应用自定义监听器,则会变得很麻烦。通过SpringFactoriesLoader机制反对主动发现默认的TestExecutionListener实现,能够解决这个问题。 具体来说,spring-test模块在其META-INF/spring.factories属性文件中的key为org.springframework.test.context.TestExecutionListener下申明所有外围默认TestExecutionListener实现。第三方框架和开发人员能够通过本人的META-INF/spring.factories属性文件以雷同的形式将本人的TestExecutionListener实现奉献到默认监听器列表中。 TestExecutionListener程序实现 当TestContext框架通过上述SpringFactoriesLoader机制发现默认TestExecutionListener实现时,实例化的监听器将应用Spring的AnnotationAwareOrderComparator进行排序,该类将应用Spring的Ordered接口和@Order注解进行排序。Spring提供的AbstractTestExecutionListener和所有默认的TestExecutionListener实现以适当的值实现Ordered。因而,第三方框架和开发人员应通过施行Ordered或申明@Order来确保按默认程序注册其默认的TestExecutionListener实现。请参阅javadoc以获取外围默认TestExecutionListener实现的getOrder()办法,以获取无关为每个外围监听器调配哪些值的详细信息。 TestExecutionListener合并实现 如果通过@TestExecutionListeners注册了自定义TestExecutionListener,则不会注册默认监听器。在大多数常见的测试计划中,这无效地迫使开发人员手动申明除任何自定义监听器之外的所有默认监听器。 上面的清单演示了这种配置款式: @ContextConfiguration@TestExecutionListeners({ MyCustomTestExecutionListener.class, ServletTestExecutionListener.class, DirtiesContextBeforeModesTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class, SqlScriptsTestExecutionListener.class})class MyTest { // class body...}这种办法的挑战在于,它要求开发人员确切地晓得默认状况下注册了哪些监听器。此外,默认的监听器集能够随版本的不同而变动-例如,在Spring框架4.1中引入了SqlScriptsTestExecutionListener,在Spring框架4.2中引入了DirtiesContextBeforeModesTestExecutionListener。此外,诸如Spring Boot和Spring Security之类的第三方框架通过应用上述主动发现机制注册了本人的默认TestExecutionListener实现。 ...

September 8, 2020 · 1 min · jiezi

关于spring:性能测试locust简介及使用

1、JMeter和Locust的比照阐明1)开源许可证工具许可范畴的问题是最重要的问题之一,因为您可能想晓得是否须要领取额定的第三方工具来实现负载测试。 如果某个工具是开源的,那么您简直能够实现为性能测试设置的任何指标,而无需任何额定付款。 开源JMeter和Locust也不例外。 JMeter和Locust都提供了许可软件许可证,该许可证反对免费软件,对软件的散发形式提出最低要求。 JMeter是由Apache开发的,它基于Apache License 2.0,而Locust是由一个由社区驱动的开发人员组成的小团队开发的 ,基于MIT许可证。 在这两种状况下,这些工具都是开源的,容许您自在应用它们,而不受任何应用限度。 2)负载测试创立和保护性能测试工作流程有三个次要步骤:创立,运行和剖析。 个别第一步是最耗时的。 编写JMeter性能测试的最罕用办法是应用其GUI模式。 JMeter GUI模式提供了一个桌面客户端,容许您轻松创立测试,而无需编写单行代码(直到您须要创立辣手的测试)。 所以最简略的场景可能如下所示: JMeter非常简单,通常,即便是没有教训的工程师也能够毫无艰难地上手。然而如果须要,您能够应用Java在GUI和非GUI模式下应用代码。 然而,因为脚本实现的复杂性(因为JMeter旨在与GUI模式一起应用)以及不足如何制作此类脚本的文档,因而这种形式在JMeter社区中并不风行。 Locust则须要python编程根底。 3)反对的协定现实状况下,您应该可能应用尽可能少的工具测试所有工具,只有它不会影响测试品质。 应用JMeter,您能够应用残缺的内置函数和第三方插件,在一个中央创立所有内容的性能测试。 您无需编码即可测试不同的协定甚至数据库。 这些包含JDBC,FTP,LDAP,SMTP等。JMeter还能够通过jar包扩大,比方加载jython,能够应用python脚本。 依据文档,Locust次要用于基于HTTP Web的测试。但能够扩大其默认性能并创立自定义Python函数来测试能够应用Python编程语言进行测试的任何内容。 4)并发用户数JMeter和Locust有齐全不同的形式来解决机器资源。 JMeter有一个基于线程的模型,它为每个用户调配一个独自的线程。 每个步骤的线程调配和基准测试须要大量资源,这就是为什么JMeter对于您能够在一台机器上模仿的用户数量十分无限的起因。 您能够在一台计算机上运行的用户数取决于许多因素,如脚本复杂性,硬件,响应大小等。 如果您的脚本很简略,JMeter容许您在一台机器上运行多达数千个,但脚本执行逐步变得不牢靠。 Locust有齐全不同的用户模仿模型,它基于事件和异步办法(协程),以gevent coroutine作为整个过程的基石。 这种实现容许Locust框架在一台机器上轻松模仿数千个并发用户,即便是在非常规的笔记本电脑上,也可同时运行外部有许多步骤的简单测试。 5)加强灵活性这两个工具提供绝对雷同的生成负载的形式 - 您能够指定在性能测试期间要应用的用户数以及它们应该减速的速度。 在JMeter中,您能够在指定字段的“线程组”控制器中配置负载:然而JMeter还有其余插件,能够让您配置非常灵活的负载。 最好的办法之一是应用Ultimate Thread Group ,它容许用户制作十分具体的加载模式: Locust有不同的办法。 当您运行性能脚本时,Locust会主动在http://localhost:8089上启动Web界面的服务器,该界面为您提供仅指定线性负载的输出元素, 当然也能够命令行执行通过参数定制。 6)脚本录制这是JMeter具备弱小劣势的中央,因为它具备脚本录制的内置性能,而Locust基本没有此性能。 除此之外,还有许多第三方插件能够为JMeter制作脚本录制。 记录此类脚本最不便的办法之一是应用BlazeMeter chrome扩大。 7)测试监控JMeter和Locust都提供了弱小的内置性能来监控性能脚本并剖析您的测试后果。 JMeter有许多不同的元素叫做监听器。 每个侦听器都提供特定类型的监督,你也能够应用许多现有的自定义监听器扩大默认库。另一方面,JMeter监听器在其运行的机器上耗费大量资源。这就是为什么通常,JMeter是以非GUI模式执行的,没有任何监听器或监控过程,在这种状况下,可应用3方工具,如BlazeMeter 。 Locust的监测能力稍弱,不过简直提供了所有可用于监控根本负载的信息。在脚本运行期间,Locust运行一个简略的Web服务器, 2、编写Locust示例代码locust_sample.py from locust import HttpUser, TaskSet, taskclass WebsiteTasks(TaskSet): def on_start(self): self.client.post("/login", { "username": "test", "password": "123456" }) @task(2) def index(self): self.client.get("/") @task(1) def about(self): self.client.get("/about/") tasks = {index: 2, about: 1} # 与装璜器成果统一class WebsiteUser(HttpUser): # task_set = WebsiteTasks # Usage of User.task_set is deprecated since version 1.0. Set the tasks attribute instead (tasks = [WebsiteTasks]) tasks = [WebsiteTasks] host = "http://debugtalk.com" min_wait = 1000 max_wait = 5000启动测试:locust -H http://debugtalk.com -f locust_sample.py ...

September 5, 2020 · 2 min · jiezi

关于spring:JAVAAutowired注解应用规则-Qualifier注解的作用是什么

1) @Autowired注解利用规定?2) @Qualifier注解的作用是什么?@Autowired由spring框架定义,用于形容类中属性或相干办法(例如构造方法)。Spring框架在我的项目运行时如果发现由他治理的Bean对象中有应用@Autowired注解形容的属性或办法,能够依照指定规定为属性赋值(DI)。其根本规定是:首先要检测容器中是否有与属性或办法参数类型相匹配的对象,如果有并且只有一个则间接注入。其次,如果检测到有多个,还会依照@Autowired形容的属性或办法参数名查找是否有名字匹配的对象,有则间接注入,没有则抛出异样。最初,如果咱们有明确要求,必须要注入类型为指定类型,名字为指定名字的对象还能够应用@Qualifier注解对其属性或参数进行形容(此注解必须配合@Autowired注解应用)。

September 4, 2020 · 1 min · jiezi

关于spring:Spring-5-中文解析核心篇IoC容器之Spring-AOP-API

上一章通过@AspectJ和基于schema的切面定义形容了Spring对AOP的反对。在本章中,咱们探讨了较低级别的Spring AOP API。对于常见的应用程序,咱们倡议将Spring AOP与AspectJ切入点一起应用,如上一章所述。 6.1 本节形容了Spring如何解决要害切入点概念。6.1.1 概念Spring的切入点模型使切入点重用不受告诉类型的影响。你能够应用雷同的切入点来定位不同的告诉。org.springframework.aop.Pointcut接口是外围接口,用于将告诉定向到特定的类和办法。残缺的接口如下: public interface Pointcut { ClassFilter getClassFilter(); MethodMatcher getMethodMatcher();}将Pointcut接口分为两局部,能够重用类和办法匹配的局部以及细粒度的合成操作(例如与另一个办法匹配器执行“联结”)。 ClassFilter接口用于将切入点限度为给定的一组指标类。如果matches()办法始终返回true,则将匹配所有指标类。以下清单显示了ClassFilter接口定义: public interface ClassFilter { boolean matches(Class clazz);}MethodMatcher接口通常更重要。残缺的接口如下: public interface MethodMatcher { boolean matches(Method m, Class targetClass); boolean isRuntime(); boolean matches(Method m, Class targetClass, Object[] args);}matchs(Method,Class)办法用于测试此切入点是否与指标类上的给定办法匹配。创立AOP代理时能够执行此评估,以防止须要对每个办法调用进行测试。如果两个参数的match办法对于给定的办法返回true,并且MethodMatcher的isRuntime()办法返回true,则在每次办法调用时都将调用三个参数的match办法。这样,切入点就能够在执行指标告诉之前立刻查看传递给办法调用的参数。 大多数MethodMatcher实现都是动态的,这意味着它们的isRuntime()办法返回false。在这种状况下,永远不会调用三参数匹配办法。 如果可能,请尝试使切入点成为动态,以容许AOP框架在创立AOP代理时缓存切入点评估的后果。6.1.2 切入点的操作Spring反对切入点上的操作(特地是联结和交加)。 联结示意两个切入点匹配其中一个的办法。交加是指两个切入点都匹配的办法。联结通常更有用。你能够通过应用org.springframework.aop.support.Pointcuts类中的静态方法或应用同一包中的ComposablePointcut类来组成切入点。然而,应用AspectJ切入点表达式通常是一种更简略的办法。然而,应用AspectJ切入点表达式通常是一种更简略的办法。 6.1.3 AspectJ 表达式切入点从2.0开始,Spring应用的最重要的切入点类型是org.springframework.aop.aspectj.AspectJExpressionPointcut。这是一个切入点,该切入点应用AspectJ提供的库来解析AspectJ切入点表达式字符串。 无关反对的AspectJ切入点原语的探讨,请参见上一章。 6.1.4 便捷切入点实现Spring提供了几种不便的切入点实现。你能够间接应用其中一些。其余的则打算在特定于应用程序的切入点中被子类化。 动态切入点 动态切入点基于办法和指标类,并且不能思考办法的参数。动态切入点足以满足大多数用处,并且最好。首次调用办法时,Spring只能评估一次动态切入点。之后,无需在每次办法调用时再次评估切入点(备注:第一次评估后进行缓存)。 本节的其余部分形容了Spring附带的一些动态切入点实现。 正则表达式切入点 指定动态切入点的一种显著办法是正则表达式。除了Spring之外,还有几个AOP框架使之成为可能。org.springframework.aop.support.JdkRegexpMethodPointcut是一个通用的正则表达式切入点它应用JDK中的正则表达式反对。 应用JdkRegexpMethodPointcut类,能够提供模式字符串的列表。如果其中任何一个匹配,则切入点的评估后果为true。(因而,后果实际上是这些切入点的并集。) 以下示例显示如何应用JdkRegexpMethodPointcut: <bean id="settersAndAbsquatulatePointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut"> <property name="patterns"> <list> <value>.*set.*</value> <value>.*absquatulate</value> </list> </property></bean>Spring提供了一个名为RegexpMethodPointcutAdvisor的便捷类,该类使咱们还能够援用一个Advice(请记住,Advice能够是拦截器、前置告诉、异样告诉等)。在幕后,Spring应用了JdkRegexpMethodPointcut。应用RegexpMethodPointcutAdvisor简化了连贯,因为一个bean同时封装了切入点和告诉,如上面的示例所示: <bean id="settersAndAbsquatulateAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice"> <ref bean="beanNameOfAopAllianceInterceptor"/> </property> <property name="patterns"> <list> <value>.*set.*</value> <value>.*absquatulate</value> </list> </property></bean>你能够将RegexpMethodPointcutAdvisor与任何Advice类型一起应用。 ...

September 3, 2020 · 5 min · jiezi

关于spring:什么是计时攻击Spring-Boot-中该如何防御

松哥最近在钻研 Spring Security 源码,发现了很多好玩的代码,抽空写几篇文章和小伙伴们分享一下。 很多人吐槽 Spring Security 比 Shiro 重量级,这个重量级不是凭空来的,分量有分量的益处,就是它提供了更为弱小的防护性能。 比方松哥最近看到的一段代码: protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { prepareTimingAttackProtection(); try { UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username); if (loadedUser == null) { throw new InternalAuthenticationServiceException( "UserDetailsService returned null, which is an interface contract violation"); } return loadedUser; } catch (UsernameNotFoundException ex) { mitigateAgainstTimingAttack(authentication); throw ex; } catch (InternalAuthenticationServiceException ex) { throw ex; } catch (Exception ex) { throw new InternalAuthenticationServiceException(ex.getMessage(), ex); }}这段代码位于 DaoAuthenticationProvider 类中,为了不便大家了解,我来简略说下这段代码的上下文环境。 ...

September 2, 2020 · 2 min · jiezi

关于spring:总结java中文件拷贝剪切的5种方式JAVA-IO基础总结第五篇

本文是Java IO总结系列篇的第5篇,前篇的拜访地址如下: 总结java中创立并写文件的5种形式-JAVA IO根底总结第一篇总结java从文件中读取数据的6种办法-JAVA IO根底总结第二篇总结java创立文件夹的4种办法及其优缺点-JAVA IO根底总结第三篇总结java中删除文件或文件夹的7种办法-JAVA IO根底总结第四篇很多敌人在看我的《java IO总结系列》之前感觉创立文件、文件夹删除文件这些根底操作真的是太简略了。但看了我的文章之后,有小伙伴找到我说:“没想到这么根底的常识外面还有这么多的门门道道,用起来很容易,真的用好也不容易”。哪一个办法用起来简略,哪一个办法在异样解决方面更加强壮,不看我的总结你可能还真的不晓得。 有趣味的理解更多的小伙伴能够关注我,我会继续的写这一系列的文章。如果您感觉我的文章对您有帮忙,请帮忙点个赞,您的反对是我不竭的创作能源! 那咱们上面就来为大家介绍本篇的内容:文件拷贝(重命名)与剪切的5种办法。首先咱们来了解以下上面的几个概念: 文件拷贝:将文件从一个文件夹复制到另一个文件夹文件剪切:将文件从以后文件夹,挪动到另一个文件夹文件重命名:将文件在以后文件夹上面改名(也能够了解为将文件剪切为以后文件夹上面的另一个文件)一、文件拷贝传统IO中的文件copy的办法,应用输入输出流,实际上就是从新创立并写入一个文件。如果指标文件曾经存在,就笼罩掉它,从新创立一个文件并写入数据。这种形式不够敌对,笼罩掉原有文件没有给出任何提醒,有可能导致原有数据的失落。 @Testvoid testCopyFile1() throws IOException { File fromFile = new File("D:\\data\\test\\newFile.txt"); File toFile = new File("D:\\data\\test2\\copyedFile.txt"); try(InputStream inStream = new FileInputStream(fromFile); OutputStream outStream = new FileOutputStream(toFile);) { byte[] buffer = new byte[1024]; int length; while ((length = inStream.read(buffer)) > 0) { outStream.write(buffer, 0, length); outStream.flush(); } }}Java NIO中文件copy的办法,应用形式简略。当指标文件曾经存在的时候会抛出FileAlreadyExistsException ,当源文件不存在的时候抛出NoSuchFileException,针对不同的异样场景给出不同的Exception,更有利于咱们写出健壮性更好的程序。 @Testvoid testCopyFile2() throws IOException { Path fromFile = Paths.get("D:\\data\\test\\newFile.txt"); Path toFile = Paths.get("D:\\data\\test2\\copyedFile.txt"); Files.copy(fromFile, toFile);}如果在指标文件曾经存在的状况下,你不想抛出FileAlreadyExistsException ,而是去笼罩它,也能够灵便的抉择应用上面的选项 ...

September 2, 2020 · 1 min · jiezi

关于spring:Spring整合MyBatis

根本步骤Step1 搭建我的项目根本框架创立controller、service、mapper、pojo包构造及相干类文件,如图: Step2 导入jar包mysql 驱动jar包mybatis jar包spring 外围包spring整合mybatis jar包spring-jdbc、spring-aop、spring-tx、spring-web jar包 Step3 编写配置文件src文件夹下创立applicationcontext.xml文件,进行如下配置: 配置DataSource bean,采纳属性注入的形式配置连贯数据库的信息配置SqlSessionFactory bean,采纳依赖注入的形式将数据源bean配置进去配置Mapper包扫描bean,将sqlsessionfactory依赖注入并配置指标扫描包门路mapper bean的id默认为Mapper文件名首字母小写配置Service bean,依赖注入mapper bean示例: <!-- 配置数据源:mybatis联合spring的包 --><bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/sxt_mybatis_learning?characterEncoding=utf8"></property> <property name="username" value="root"></property> <property name="password" value="root"></property></bean><!--配置SqlSession工厂Bean--><bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref = "datasource"></property></bean><!--配置Mapper包扫描bean--><bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactory" ref="factory"></property> <property name="basePackage" value="com.gcp.mapper"></property></bean><!--配置service bean--><bean id="flowerService" class="com.gcp.service.impl.FlowerServiceImpl"> <property name="flowerMapper" ref="flowerMapper"></property></bean>Step4 Mapper层在Mapper编写数据库操作代码 Step5 Service层申明Mapper属性,并提供getter、setter办法编写service业务代码Step6 Controller层申明Service属性在init办法中实现Spring容器内资源的初始化加载,获取业务层对象赋值给service属性编写servlet层代码示例: @Overridepublic void init() throws ServletException { ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext()); flowerService = (FlowerService) ac.getBean("flowerService");}Step7 配置我的项目的web.xml文件配置Spring环境加载文件的门路参数配置监听器示例: <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationcontext.xml</param-value></context-param><listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>

September 1, 2020 · 1 min · jiezi

关于spring:面试官就问个Spring容器初始化和Bean对象的创建你讲一小时了

前言spring作为一个容器,能够治理对象的生命周期、对象与对象之间的依赖关系。能够通过配置文件,来定义对象,以及设置其与其余对象的依赖关系。 main测试类 public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); Bean bean = applicationContext.getBean(Bean.class); System.out.println(bean); }ClassPathXmlApplicationContext类application建设当前,能够通过refresh()进行重建,这样会将原来的application销毁,而后从新执行初始化构造方法 public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); //设置配置文件 setConfigLocations(configLocations); if (refresh) { //外围办法 refresh(); } }AbstractApplicationContext类refresh办法 @Override public void refresh() throws BeansException, IllegalStateException { // 同步,避免你在初始化的过程中被打断 synchronized (this.startupShutdownMonitor) { // 筹备工作 prepareRefresh(); // 配置文件被拆分成Bean定义,注册在BeanFactory中。 // 也就是Map<beanName, beanDefinition> ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // 到这一步,所有的Bean加载和注册都曾经实现,然而还没开始初始化 // 如果实现了 BeanFactoryPostProcessor 接口,能够在初始化的时候做点事件 postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. // 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 办法 invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. // 注册 BeanPostProcessor 的实现类,留神看和 BeanFactoryPostProcessor 的区别 // 此接口两个办法: postProcessBeforeInitialization 和 postProcessAfterInitialization // 两个办法别离在 Bean 初始化之前和初始化之后失去执行。留神,到这里 Bean 还没初始化 registerBeanPostProcessors(beanFactory); // Initialize message source for this context. // 初始化以后 ApplicationContext 的 MessageSource, 国际化等 initMessageSource(); // Initialize event multicaster for this context. // 初始化以后 ApplicationContext 的事件播送器 initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. // 从办法名就能够晓得,典型的模板办法(钩子办法), // 具体的子类能够在这里初始化一些非凡的 Bean(在初始化 singleton beans 之前) onRefresh(); // Check for listener beans and register them. // 注册监听,监听器须要实现 ApplicationListener 接口 registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. // 初始化所有的singletons , non-lazy除外 // 次要办法 finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. // 最初一步,公布事件播送 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }obtainFreshBeanFactory()办法1、初始化 BeanFactory-》DefaultListableBeanFactory.class ...

September 1, 2020 · 4 min · jiezi

关于spring:总结删除文件或文件夹的7种方法JAVA-IO基础总结第4篇

本文是Java IO总结系列篇的第4篇,前篇的拜访地址如下: 总结java中创立并写文件的5种形式-JAVA IO根底总结第一篇总结java从文件中读取数据的6种办法-JAVA IO根底总结第二篇总结java创立文件夹的4种办法及其优缺点-JAVA IO根底总结第三篇如果您浏览实现,感觉此文对您有帮忙,请给我点个赞,您的反对是我不竭的创作能源。 为了不便大家了解,我特意制作了本文对应的视频:总结删除文件或者文件夹的7种办法一、删除文件或文件夹的四种根底办法上面的四个办法都能够删除文件或文件夹,它们的共同点是:当文件夹中蕴含子文件的时候都会删除失败,也就是说这四个办法只能删除空文件夹。 须要留神的是:传统IO中的File类和NIO中的Path类既能够代表文件,也能够代表文件夹。File类的delete()File类的deleteOnExit()Files.delete(Path path)Files.deleteIfExists(Path path);它们之间的差别: 胜利的返回值是否能判断文件夹不存在导致失败是否能判断文件夹不为空导致失败备注File类的delete()true不能(返回false)不能(返回false)传统IOFile类的deleteOnExit()void不能,但不存在就不会去执行删除不能(返回void)传统IO,这是个坑,防止应用Files.delete(Path path)voidNoSuchFileExceptionDirectoryNotEmptyExceptionNIO,笔者举荐应用Files.deleteIfExists(Path path);truefalseDirectoryNotEmptyExceptionNIO由下面的比照能够看出,传统IO办法删除文件或文件夹,再删除失败的时候,最多返回一个false。通过这个false无奈挖掘删除失败的具体起因,是因为文件自身不存在删除失败?还是文件夹不为空导致的删除失败?NIO 的办法在这一点上,就做的比拟好,删除胜利或失败都有具体的返回值或者异样信息,这样有利于咱们在删除文件或文件夹的时候更好的做程序的异样解决须要留神的是传统IO中的deleteOnExit办法,笔者感觉应该防止应用它。它永远只返回void,删除失败也不会有任何的Exception抛出,所以我倡议不要用,免得在你删除失败的时候没有任何的响应,而你可能误以为删除胜利了。//false只能通知你失败了 ,然而没有给出任何失败的起因@Testvoid testDeleteFileDir1() { File file = new File("D:\\data\\test"); boolean deleted = file.delete(); System.out.println(deleted);}//void ,删除失败没有任何提醒,应防止应用这个办法,就是个坑@Testvoid testDeleteFileDir2() { File file = new File("D:\\data\\test1"); file.deleteOnExit();}//如果文件不存在,抛出NoSuchFileException//如果文件夹外面蕴含文件,抛出DirectoryNotEmptyException@Testvoid testDeleteFileDir3() throws IOException { Path path = Paths.get("D:\\data\\test1"); Files.delete(path); //返回值void}//如果文件不存在,返回false,示意删除失败(文件不存在)//如果文件夹外面蕴含文件,抛出DirectoryNotEmptyException@Testvoid testDeleteFileDir4() throws IOException { Path path = Paths.get("D:\\data\\test1"); boolean result = Files.deleteIfExists(path); System.out.println(result);}归根结底,倡议大家应用java NIO的Files.delete(Path path)和Files.deleteIfExists(Path path);进行文件或文件夹的删除。 二、如何删除整个目录或者目录中的局部文件上文曾经说了,那四个API删除文件夹的时候,如果文件夹蕴含子文件,就会删除失败。那么,如果咱们的确想删除整个文件夹,该怎么办? 前提筹备为了不便咱们前面进行试验,先去创立这样一个目录构造,“.log”结尾的是数据文件,其余的是文件夹 ...

September 1, 2020 · 2 min · jiezi

关于spring:深度分析java设计模式中的原型模式看完就没有说不懂的

前言原型模式(Prototype模式)是指:用原型实例指定创建对象的品种,并且通过拷贝这些原型,创立新的对象原型模式是一种创立型设计模式,容许一个对象再创立另外一个可定制的对象,无需晓得如何创立的细节。工作原理:通过将一个原型对象传给那个要动员创立的对象,这个要动员创立的对象通过申请原型对象拷贝它们本人来施行创立,即 对象.clone()形象的了解:孙大圣插入猴毛,变出其余孙大圣 原型模式类图实例 Prototype:原型类,申明一个克隆本人的接口ConcretePrototype:具体的原型类,实现一个克隆本人的操作。Client:让一个原型对象克隆本人,从而创立一个新的对象(属性一样)原型模式java代码实例Sheep类实现Cloneable接口重写clone办法 public class Sheep implements Cloneable{ private String name; private int age; private String color; public Sheep(String name, int age, String color) { this.name = name; this.age = age; this.color = color; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } @Override public String toString() { return "Sheep{" + "name='" + name + '\'' + ", age=" + age + ", color='" + color + '\'' + '}'; } //克隆该实例,应用默认的clone办法来实现 @Override protected Object clone() { Sheep sheep = null; try { sheep = (Sheep) super.clone(); } catch (Exception e) { System.out.println(e.getMessage()); } return sheep; }}Client类测试创立多个Sheep的实例,查看是否状态统一。 ...

August 31, 2020 · 8 min · jiezi

关于spring:总结java创建文件夹的4种方法及其优缺点JAVA-IO基础总结第三篇

本文是Java IO总结系列篇的第3篇,前篇的拜访地址如下: 总结java中创立并写文件的5种形式-JAVA IO根底总结第一篇总结java从文件中读取数据的6种办法-JAVA IO根底总结第二篇本文为大家介绍Java IO-创立文件夹的四种办法,及其优缺点的解析。如果您浏览实现,感觉此文对您有帮忙,请给我点个赞,您的反对是我不竭的创作能源。 1.传统API创立文件夹形式Java传统的IO API种应用java.io.File类中的file.mkdir()和file.mkdirs()办法创立文件夹 file.mkdir()创立文件夹胜利返回true,失败返回false。如果被创立文件夹的父文件夹不存在也返回false.没有异样抛出。file.mkdirs()创立文件夹连同该文件夹的父文件夹,如果创立胜利返回true,创立失败返回false。创立失败同样没有异样抛出。@Testvoid testCreateDir1() { //“D:\data111”目录当初不存在 String dirStr = "D:\\data111\\test"; File directory = new File(dirStr); //mkdir boolean hasSucceeded = directory.mkdir(); System.out.println("创立文件夹后果(不含父文件夹):" + hasSucceeded); //mkdirs hasSucceeded = directory.mkdirs(); System.out.println("创立文件夹后果(蕴含父文件夹):" + hasSucceeded);}输入后果如下:应用mkdir创立失败,应用mkdirs创立胜利。 创立文件夹后果(不含父文件夹):false创立文件夹后果(蕴含父文件夹):true大家能够看到,mkdir和mkdirs尽管能够创立文件,然而它们在异样解决的环节做的十分不敌对。创立失败之后对立返回false,创立失败的起因没有阐明。是父文件夹不存在所以创立失败?还是文件夹曾经存在所以创立失败?还是因为磁盘IO起因导致创立文件夹失败? 2. Java NIO创立文件夹为了解决传统IO创立文件夹中异样失败解决问题不明确的问题,在Java的NIO中进行了改良。 2.1. Files.createDirectory创立文件夹如果被创立文件夹的父文件夹不存在,则抛出NoSuchFileException.如果被创立的文件夹曾经存在,则抛出FileAlreadyExistsException.如果因为磁盘IO出现异常,则抛出IOException.Path path = Paths.get("D:\\data222\\test");Path pathCreate = Files.createDirectory(path);2.2.Files.createDirectories创立文件夹及其父文件夹如果被创立文件夹的父文件夹不存在,就创立它如果被创立的文件夹曾经存在,就是用曾经存在的文件夹,不会反复创立,没有异样抛出如果因为磁盘IO出现异常,则抛出IOException.Path path = Paths.get("D:\\data222\\test");Path pathCreate = Files.createDirectorys(path);另外大家要留神:NIO的API创立的文件夹返回值是Path,这样不便咱们在创立实现文件夹之后持续向文件夹外面写入文件数据等操作。比传统IO只返回一个boolean值要好得多。 欢送关注我的博客,外面有很多精品合集本文转载注明出处(必须带连贯,不能只转文字):字母哥博客。感觉对您有帮忙的话,帮我点赞、分享!您的反对是我不竭的创作能源! 。另外,笔者最近一段时间输入了如下的精品内容,期待您的关注。 《手摸手教你学Spring Boot2.0》《Spring Security-JWT-OAuth2一本通》《实战前后端拆散RBAC权限管理系统》《实战SpringCloud微服务从青铜到王者》《VUE深入浅出系列》

August 31, 2020 · 1 min · jiezi

关于spring:一个诡异的登录问题

美妙周末,从解 BUG 开始! 周五原本想早点上班,临了有一个简略的需要忽然提上来,心想着整完了就走,没想到一下折腾了 1 个多小时才搞定,欢快的周末就从加班中开启了。回到家里把这件事复盘一下,小伙伴们看看是否可能从中 GET 到一些未知的货色。 需要是这样的: 我的项目是 Spring Boot 我的项目,里边对申请进行了划分,有的申请是 HTTP 协定,有的申请是 HTTPS 协定,我的项目规定,有一些申请必须是 HTTPS 协定,例如 /https 接口,该接口必须应用 HTTPS 协定拜访,如果用户应用了 HTTP 协定拜访,那么会主动产生申请重定向,重定向到 HTTPS 协定上;同时也有一些申请必须是 HTTP 协定,例如 /http 接口,该接口必须应用 HTTP 协定拜访,如果用户应用了 HTTPS 协定拜访,那么会主动产生申请重定向,重定向到 HTTP 协定上。对于一些没有明确规定的接口,当用户拜访 HTTP 协定时,不须要主动跳转到 HTTPS 协定上,即用户如果应用 HTTP 协定就是 HTTP 协定,用户如果应用 HTTPS 协定就是 HTTPS 协定。 这个工作切实是小 case,因为我的项目自身曾经反对 HTTPS 了,我只须要再增加一个 HTTP 监听的端口即可(Spring Boot 中配置 Https),增加如下配置: @Configurationpublic class TomcatConfig { @Bean TomcatServletWebServerFactory tomcatServletWebServerFactory() { TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); factory.addAdditionalTomcatConnectors(createTomcatConnector()); return factory; } private Connector createTomcatConnector() { Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol"); connector.setScheme("http"); connector.setPort(8080); return connector; }}增加实现后,我的项目启动日志如下: ...

August 31, 2020 · 2 min · jiezi

关于spring:归纳从文件中读取数据的六种方法JAVA-IO基础总结第2篇

在上一篇文章中,我为大家介绍了《5种创立文件并写入文件数据的办法》,本节咱们为大家来介绍6种从文件中读取数据的办法. 另外为了不便大家了解,我为这一篇文章录制了对应的视频:总结java从文件中读取数据的6种办法-JAVA IO根底总结第二篇Scanner(Java 1.5) 按行读数据及String、Int类型等按分隔符读数据。Files.lines, 返回Stream(Java 8) 流式数据处理,按行读取Files.readAllLines, 返回List<String>(Java 8)Files.readString, 读取String(Java 11), 文件最大 2G.Files.readAllBytes, 读取byte[](Java 7), 文件最大 2G.BufferedReader, 经典形式 (Java 1.1 -> forever)能够说,每一种办法都有本人的实用场景,下文中为大家来一一介绍。 如果您看完我的创作,感觉您有帮忙的话,请帮忙点赞,您的反对是我不竭的创作能源! 1.Scanner第一种形式是Scanner,从JDK1.5开始提供的API,特点是能够按行读取、按宰割符去读取文件数据,既能够读取String类型,也能够读取Int类型、Long类型等根底数据类型的数据。 @Testvoid testReadFile1() throws IOException { //文件内容:Hello World|Hello Zimug String fileName = "D:\\data\\test\\newFile4.txt"; try (Scanner sc = new Scanner(new FileReader(fileName))) { while (sc.hasNextLine()) { //按行读取字符串 String line = sc.nextLine(); System.out.println(line); } } try (Scanner sc = new Scanner(new FileReader(fileName))) { sc.useDelimiter("\\|"); //分隔符 while (sc.hasNext()) { //按分隔符读取字符串 String str = sc.next(); System.out.println(str); } } //sc.hasNextInt() 、hasNextFloat() 、根底数据类型等等等等。 //文件内容:1|2 fileName = "D:\\data\\test\\newFile5.txt"; try (Scanner sc = new Scanner(new FileReader(fileName))) { sc.useDelimiter("\\|"); //分隔符 while (sc.hasNextInt()) { //按分隔符读取Int int intValue = sc.nextInt(); System.out.println(intValue); } }}下面的办法输入后果如下: ...

August 31, 2020 · 2 min · jiezi

关于spring:springboot2之优雅处理返回值

前言最近项目组有个老我的项目要进行前后端拆散革新,应前端同学的要求,其后端提供的返回值格局需形如 { "status": 0, "message": "success", "data": { }}不便前端数据处理。要实现前端同学这个需要,其实也挺简略的,仅需做如下革新,新增一个返回对象,形如 @Data@AllArgsConstructor@NoArgsConstructor@Builderpublic class Result<T> { public static final int success = 0; public static final int fail = 1; private int status = success; private String message = "success"; private T data;}而后controller革新成如下 @RestController@RequestMapping("/user")@Slf4jpublic class UserController { @Autowired private UserService userService; @PostMapping(value="/add") public Result<UserDTO> addUser(@Valid UserDTO userDTO, BindingResult bindingResult){ Result<UserDTO> result = new Result<>(); if (bindingResult.hasErrors()){ return getUserFailResult(bindingResult, result); } saveUser(userDTO, result); return result; }}仅仅须要这么革新就能够满足前端同学的述求。但这边存在一个问题就是,这个我的项目后端接口的contoller之前都是间接返回业务bean对象,形如下 ...

August 30, 2020 · 3 min · jiezi

关于spring:Spring-Boot中MyBatis业务实现分析

首先咱们晓得MyBatis所做的事件就是将JDBC操作做了封装以及优化,其目标是让开发人员更不便的对数据库进行操作 在MyBaits框架中由两种SQL语句映射形式,一是间接写在XML文件中的<mapper>元素外部,还有就是通过注解的形式实现, 一、通过XML实现映射:要留神XML文件中的id值要与办法名称保持一致~~~~ 二、通过注解的形式:先接着下面的代码说一下留神的注解:@Mapper:应用在接口上的注解,被其润饰的接口会由mybaits创立一个实现类,并交由spring治理。 通过这个注解咱们能够不用本人去实现办法,而只须要在接口中申明该办法的形象,实现SQL则只须要在该形象办法上增加所要执行的SQL的注解就行。 这样咱们的SQL语句就和咱们的办法关联上了,最初通过依赖注入的形式将这个接口的实现类对象增加到测试类中 上图的中的goodsDao变量中就注入了一个GoodsDao类型的对象,这个对象齐全由框架本人生产进去。 业务的实现无论是哪一种形式实现sql业务都是基于mybatis实现的,咱们能够剖析一下在实现业务的过程具体是如何实现的: 1、在下面的代码里咱们的sql语句是写在GoodsDao接口中的注解上的,所应用的办法也是在其中定义的,

August 29, 2020 · 1 min · jiezi

关于spring:总结java中创建并写文件的5种方式

在java中有很多的办法能够创立文件写文件,你是否真的认真的总结过?上面笔者就帮大家总结一下java中创立文件的五种办法。 Files.newBufferedWriter(Java 8)Files.write(Java 7 举荐)PrintWriterFile.createNewFileFileOutputStream.write(byte[] b) 管道流实际上不只这5种,通过管道流的排列组合,其实有更多种,然而笔者总结的这五种能够说是最罕用及最佳实际,前提小常识以前我在写技术文章波及到“流敞开”、“连贯敞开”的时候,常常有人留言:“还写技术文章,写个流都不晓得close()”,这种留言我遇到过无数回!在本文中大量的应用到了try-with-resources语法,这个语法真的是很久的了,然而确实还有小伙伴不晓得(晓得的小伙伴就略过吧)。我还是说一下,下文中的管道流不是我没close,是主动敞开close的。 try(管道流、连贯等实现了Closeable接口的类){ //这里应用类对象操作}//用try()蕴含起来,就不必在finally外面本人手动的去 Object.close()了,会主动的敞开1. Java 8 Files.newBufferedWriterjava8 提供的newBufferedWriter能够创立文件,并向文件内写入数据。能够通过追加写模式,向文件内追加内容。 @Testvoid testCreateFile1() throws IOException { String fileName = "D:\\data\\test\\newFile.txt"; Path path = Paths.get(fileName); // 应用newBufferedWriter创立文件并写文件 // 这里应用了try-with-resources办法来敞开流,不必手动敞开 try (BufferedWriter writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) { writer.write("Hello World -创立文件!!"); } //追加写模式 try (BufferedWriter writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8, StandardOpenOption.APPEND)){ writer.write("Hello World -字母哥!!"); }}2. Java 7 Files.write上面的这种形式Files.write,是笔者举荐的形式,语法简略,而且底层是应用Java NIO实现的。同样提供追加写模式向曾经存在的文件种追加数据。这种形式是实现文本文件简略读写最方便快捷的形式。 @Testvoid testCreateFile2() throws IOException { String fileName = "D:\\data\\test\\newFile2.txt"; // 从JDK1.7开始提供的办法 // 应用Files.write创立一个文件并写入 Files.write(Paths.get(fileName), "Hello World -创立文件!!".getBytes(StandardCharsets.UTF_8)); // 追加写模式 Files.write( Paths.get(fileName), "Hello World -字母哥!!".getBytes(StandardCharsets.UTF_8), StandardOpenOption.APPEND);}3. PrintWriterPrintWriter是一个比拟古老的文件创建及写入形式,从JDK1.5就曾经存在了,比拟有特点的是:PrintWriter的println办法,能够实现一行一行的写文件。 ...

August 28, 2020 · 1 min · jiezi

关于spring:关于工厂模式控制反转的一些理解

一、什么是工厂模式顾名思义,工厂模式能够看作是一个生产对象的工厂,其中对象的生产办法由具体的实现类定义(对象中蕴含什么不能由指定创立的类抉择,应用工厂创建对象的类只能抉择工厂中有的对象类型),就如果咱们去汽车厂买车,咱们能够依据厂里的汽车款式抉择一款,但咱们没方法指定要一款完全符合本人想法的车(须要如此定制的办法也不须要应用到工厂模式,不如本人创立一个类),工厂中只会依照既定的模型去发明对象咱们能够指定的是这些模型中某些参数的值比方汽车的排量,油耗,但无奈指定模型中没有的货色比方要在汽车上加个火箭推进器就不行,因为工厂中临时还没有这样的模型*(不过咱们能够在工厂里增加一个这样的模型)。*总而言之,工厂模式就是将咱们须要的对象以固定模型的形式寄存在工厂中,在咱们须要这种模型的对象时,咱们只须要往其中传入一些具体的参数就能失去相应的对象,二、什么是管制反转作为一个初学者在翻阅[维基百科对管制反转的定义](https://zh.wikipedia.org/wiki/%E6%8E%A7%E5%88%B6%E5%8F%8D%E8%BD%AC)之后得出的论断:角色上的反转,失常状况下的对象都是由开发者去new进去的,管制反转就是将创建对象的势力交给某局部程序(尽管这部分程序也是开发者写的,但咱们不探讨。。。),咱们将创建对象的细节交给代码去治理,咱们在应用的时候就不用去关怀具体的创立细节了,始终到这里,其实和咱们本人手动创建对象并没有什么不同,创建对象的流程实质上没有变动,只是咱们写了一段代码,让这段代码帮咱们去做了这件事,也就是所谓“角色反转”那么管制反转的作用如何体现呢?管制反转最常见的形式就是**依赖注入**,通过内部容器来治理对象,在对象被创立时从内部进行注入,其被注入对象的形式是被动的,是由内部容器被动为其注入的还有一种形式是**依赖查找**,会被动去找寻相应对象类型、名称的对象实例将其注入[知乎上一篇文章说的很艰深](https://zhuanlan.zhihu.com/p/77415657)总的来说,管制反转的思维能够大幅度的升高程序之间的耦合度,ioc作为连贯程序与程序之前的桥梁,把对象的创立、治理综合起来解决,在须要某段代码须要对象时就去提取相应的对象。这个提取的过程就是依赖注入或者依赖查看,整个我的项目程序之间的关系、类与类之间的关系就全副存由ioc治理了。如此一来,咱们无论要批改哪个类中的数据都不用思考那么多各个类之间是否有依赖关系了,因为所有关系咱们都交给了ioc。(当然只有ioc中存在的关系能力这样~~~~)三、spring中的工厂与管制反转管制反转在spring中有极其重要的作用,工厂模式就是管制反转思维的局部体现~~~~,spring中的ioc容器用来存储、治理工厂创立的对象,

August 27, 2020 · 1 min · jiezi

关于spring:一次完整的JVM堆外内存泄漏故障排查记录

前言记录一次线上JVM堆外内存透露问题的排查过程与思路,其中夹带一些JVM内存分配机制以及罕用的JVM问题排查指令和工具分享,心愿对大家有所帮忙。 在整个排查过程中,我也走了不少弯路,然而在文章中我依然会把残缺的思路和想法写进去,当做一次经验教训,给前人参考,文章最初也总结了下内存透露问题疾速排查的几个准则。 本文的次要内容: 故障形容和排查过程故障起因和解决方案剖析JVM堆内内存和堆外内存调配原理罕用的过程内存透露排查指令和工具介绍和应用文章撰写不易,请大家多多反对我的原创技术公众号:后端技术漫谈故障形容8月12日中午午休工夫,咱们商业服务收到告警,服务过程占用容器的物理内存(16G)超过了80%的阈值,并且还在一直回升。 监控零碎调出图表查看: 像是Java过程产生了内存透露,而咱们堆内存的限度是4G,这种大于4G快要吃满内存应该是JVM堆外内存透露。 确认了下过后服务过程的启动配置: -Xms4g -Xmx4g -Xmn2g -Xss1024K -XX:PermSize=256m -XX:MaxPermSize=512m -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=80尽管当天没有上线新代码,然而当天上午咱们正在应用音讯队列推送历史数据的修复脚本,该工作会大量调用咱们服务其中的某一个接口,所以初步狐疑和该接口无关。 下图是该调用接口当天的访问量变动: 能够看到案发过后调用量相比失常状况(每分钟200+次)进步了很多(每分钟5000+次)。 咱们临时让脚本进行发送音讯,该接口调用量降落到每分钟200+次,容器内存不再以极高斜率回升,所有仿佛复原了失常。 接下来排查这个接口是不是产生了内存透露。 排查过程首先咱们先回顾下Java过程的内存调配,不便咱们上面排查思路的论述。 以咱们线上应用的JDK1.8版本为例。JVM内存调配网上有许多总结,我就不再进行二次创作。 JVM内存区域的划分为两块:堆区和非堆区。 堆区:就是咱们熟知的新生代老年代。非堆区:非堆区如图中所示,有元数据区和间接内存。 这里须要额定留神的是:永恒代(JDK8的原生去)寄存JVM运行时应用的类,永恒代的对象在full GC时进行垃圾收集。 温习完了JVM的内存调配,让咱们回到故障上来。 堆内存剖析虽说一开始就根本确认与堆内存无关,因为泄露的内存占用超过了堆内存限度4G,然而咱们为了保险起见先看下堆内存有什么线索。 咱们察看了新生代和老年代内存占用曲线以及回收次数统计,和平常一样没有大问题,咱们接着在事故现场的容器上dump了一份JVM堆内存的日志。 堆内存Dump堆内存快照dump命令: jmap -dump:live,format=b,file=xxxx.hprof pid画外音:你也能够应用jmap -histo:live pid间接查看堆内存存活的对象。导出后,将Dump文件下载回本地,而后能够应用Eclipse的MAT(Memory Analyzer)或者JDK自带的JVisualVM关上日志文件。 应用MAT关上文件如图所示: 能够看到堆内存中,有一些nio无关的大对象,比方正在接管音讯队列音讯的nioChannel,还有nio.HeapByteBuffer,然而数量不多,不能作为判断的根据,先放着察看下。 下一步,我开始浏览该接口代码,接口外部次要逻辑是调用团体的WCS客户端,将数据库表中数据查表后写入WCS,没有其余额定逻辑 察觉没有什么非凡逻辑后,我开始狐疑WCS客户端封装是否存在内存透露,这样狐疑的理由是,WCS客户端底层是由SCF客户端封装的,作为RPC框架,其底层通信传输协定有可能会申请间接内存。 是不是我的代码登程了WCS客户端的Bug,导致一直地申请间接内存的调用,最终吃满内存。 我分割上了WCS的值班人,将咱们遇到的问题和他们形容了一下,他们回复咱们,会在他们本地执行下写入操作的压测,看看能不能复现咱们的问题。 既然期待他们的反馈还须要工夫,咱们就筹备先本人推敲下起因。 我将狐疑的眼光停留在了间接内存上,狐疑是因为接口调用量过大,客户端对nio使用不当,导致应用ByteBuffer申请过多的间接内存。 画外音:最终的后果证实,这一个先入为主的思路导致排查过程走了弯路。在问题的排查过程中,用正当的猜想来放大排查范畴是能够的,但最好先把每种可能性都列分明,在发现自己深刻某个可能性无果时,要及时回头认真扫视其余可能性。沙箱环境复现为了能还原过后的故障场景,我在沙箱环境申请了一台压测机器,来确保和线上环境统一。 首先咱们先模仿内存溢出的状况(大量调用接口): 咱们让脚本持续推送数据,调用咱们的接口,咱们继续察看内存占用。 当开始调用后,内存便开始持续增长,并且看起来没有被限制住(没有因为限度触发Full GC)。 接着咱们来模仿下平时失常调用量的状况(失常量调用接口): 咱们将该接口平时失常的调用量(比拟小,且每10分钟进行一次批量调用)切到该压测机器上,失去了下图这样的老生代内存和物理内存趋势: 问题来了:为何内存会一直往上走吃满内存呢? 过后猜想是因为JVM过程并没有对于间接内存大小进行限度(-XX:MaxDirectMemorySize),所以堆外内存一直上涨,并不会触发FullGC操作。 上图可能得出两个论断: 在内存泄露的接口调用量很大的时候,如果恰好堆内老生代等其余状况始终不满足FullGC条件,就始终不会FullGC,间接内存一路上涨。而在平时低调用量的状况下, 内存透露的比较慢,FullGC总会到来,回收掉泄露的那局部,这也是平时没有出问题,失常运行了很久的起因。因为下面提到,咱们过程的启动参数中并没有限度间接内存,于是咱们将-XX:MaxDirectMemorySize配置加上,再次在沙箱环境进行了测验。 后果发现,过程占用的物理内存仍然会一直上涨,超出了咱们设置的限度,“看上去”配置仿佛没起作用。 ...

August 27, 2020 · 4 min · jiezi

关于spring:不会吧做了这么久开发还有不会NIO的看看BAT大佬是怎么用的吧

前言在将NIO之前,咱们必须要理解一下Java的IO局部常识。BIO(Blocking IO)阻塞IO,在Java中次要就是通过ServerSocket.accept()实现的。NIO(Non-Blocking IO)非阻塞IO,在Java次要是通过NIOSocketChannel + Seletor实现的。AIO(Asyc IO)异步IO,目前不做学习。BIO简略实现服务器和客户端 package net.io;import net.ByteUtil;import java.io.*;import java.net.ServerSocket;import java.net.Socket;//NIO(NonBlocking IO)非阻塞IO//通过一个事件监听器,吧这些客户端的连贯保存起来,如果有工夫产生再去解决,没工夫产生不解决public class Server { public Server(int port) { try { //创立服务器端,监听端口port ServerSocket serverSocket = new ServerSocket(port); //对客户端进行一个监听操作,如果有连贯过去,就将连贯返回(socket)-----阻塞办法 while (true) { //监听,阻塞办法 Socket socket = serverSocket.accept(); //每个服务器和客户端的通信都是针对与socket进行操作 System.out.println("客户端" + socket.getInetAddress()); InputStream inputStream = socket.getInputStream(); ObjectInputStream ois = new ObjectInputStream(inputStream); //获取客户端发送的message Object get = ois.readObject(); System.out.println("接管到的音讯为:" + get); //服务器须要给客户端进行一个回应 OutputStream outputStream = socket.getOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(outputStream); String message = "客户端你好,我是服务器端"; //我这里写了,不代表发送了,常识写到了输入流的缓冲区 oos.writeObject(message); //发送并清空 oos.flush(); } } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { new Server(7000); }}package net.io;import net.ByteUtil;import java.io.*;import java.net.Socket;public class Client { public Client(int port){ try { Socket socket = new Socket("localhost",port); //inputStream是输出流,从里面接管信息 //outpurStream是输入流, 往外面输入信息 OutputStream outputStream = socket.getOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(outputStream); //发送的信息 String message = "服务器你好,我是客户端"; //我这里写了,不代表发送了,常识写到了输入流的缓冲区 oos.writeObject(message); //发送并清空 oos.flush(); //接管服务器的回应 InputStream inputStream = socket.getInputStream(); ObjectInputStream ois = new ObjectInputStream(inputStream); Object get = ois.readObject(); System.out.println("接管的信息为:" + get); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { new Client(7000); }}针对于BIO,为什么是阻塞IO,是因为BIO是基于Socket实现数据的读写操作,Server调用accept()办法继续监听socket连贯,所以就阻塞在accept()这里(前面的操作如果没有socket连贯则无奈执行),那这样就代表服务器只能同时解决一个socket的操作。所以后序咱们通过为socket连贯创立一个线程执行,这样就能够增大服务器解决连贯的数量了。然而新的问题也就进去了,如果客户端的连贯很多,那么就会导致服务器创立很多的线程对socket进行解决,如果服务器端不断开连接的话,那么对应的线程也不会被销毁,这样大数量的线程的保护非常耗费资源。针对于这种状况设计出了Java的NIO。 ...

August 26, 2020 · 3 min · jiezi

关于spring:精讲响应式WebClient第6篇请求失败自动重试机制强烈建议你看一看

本文是精讲响应式WebClient第6篇,前篇的blog拜访地址如下: 精讲响应式webclient第1篇-响应式非阻塞IO与根底用法精讲响应式WebClient第2篇-GET申请阻塞与非阻塞调用办法详解精讲响应式WebClient第3篇-POST、DELETE、PUT办法应用精讲响应式WebClient第4篇-文件上传与下载精讲响应式WebClient第5篇-申请超时设置与异样解决在上一篇咱们为大家介绍了WebClient的异样解决办法,咱们能够对指定的异样进行解决,也能够分类解决400-499、500-599状态码的HTTP异样。咱们本节为大家介绍的实际上是另外一种异样解决机制:申请失败之后主动重试。当WebClient发动申请,没有失去失常的响应后果,它就会每隔一段时间再次发送申请,能够发送n次,这个n是咱们自定义的。n次申请都失败了,最初再将异样抛出,能够通过咱们上一节交给大家的办法进行异样解决。也就是针对连贯超时异样、读写超时异样等,或者是HTTP响应后果为非正常状态码(不是200状态码段),都在主动重试机制的领域内。 如果您感觉我的文章对您有帮忙的话,请帮忙点赞或分享,您的反对是我不竭的创作能源! 一、申请异样重试上面的代码是申请"http://jsonplaceholder.typicode.com" 网站的服务,该网站是一个收费提供HTTP申请测试的服务端网站,咱们能够用它测试WebClient。须要留神的是:失常的GET办法申请地址是"/posts/1",我特意的把它写错成为"/postss/1",这样能够触发404资源无奈找到的异样。 public class ReTryTest { @Test public void testRetry() { WebClient webClient = WebClient.builder() .baseUrl("http://jsonplaceholder.typicode.com") .build(); Mono<String> mono = webClient .get() //GET 申请 .uri("/postss/1") // 申请门路,留神为了制作异样,这里是错的 .retrieve() //获取申请后果 .bodyToMono(String.class) //用Mono接管单个非汇合对象数据 .doOnError(Exception.class, err -> { //解决异样 System.out.println(LocalDateTime.now() + "---产生谬误:" +err.getMessage() ); }) .retry(3); System.out.println("=====" + mono.block()); } }doOnError异样解决是咱们在上一节文章中为大家介绍的异样处理函数,咱们在这里打印日志,察看重试次数retry(3)就是重点了,示意申请失败之后重试3次申请。也能够应用retry()无参办法,不设置次数,能够有限重试。这样显然不好,咱们个别不必。上面是doOnError中打印的控制台输入内容,一共打印了4次。(一次失败 + 三次重试失败) 二、重试工夫距离设置下面的申请重试办法,申请失败之后立刻重试,在很短的工夫内就实现了3次重试。如果这是在生产环境下,可能你的服务端因为资源缓和造成申请响应超时等异样,这种重试机制无疑会让本就不堪重负的服务端雪上加霜。咱们上面交给大家一种为重试设置工夫距离的办法: .retryBackoff(3, Duration.ofSeconds(5));第一个参数依然示意重试3次第二个参数示意按指数增长的工夫距离重试,第一次重试距离5秒,第二次距离10秒(5 x2),第三次距离20秒(5x2x2)源码如下: 三、retryWhen办法下面的retryBackoff办法尽管曾经肯定水平上缓解了申请重试导致的服务端的压力,然而它还是不分场景的一直重试。 在理论的开发中,能够申请重试的场景应该是:网络异样、申请超时异样、服务端忽然面临高并发导致的长期解决能力有余导致的超时等这种因为内部起因导致的异样场景。对于那些因为程序员编写的bug、资源拜访权限有余、资源找不到、HTTP版本不受反对等造成的异样,重试一万次也不会胜利,反而可能因为你一直的重试造成服务器解体。所以说Webclient曾经在源码中,将retryBackoff()标记为废除,倡议应用retryWhen()代替它。retryWhen()能够指定针对某些异样进行重试,其余异样不做重试。 为了应用retryWhen(),须要引入上面的包 <dependency> <groupId>io.projectreactor.addons</groupId> <artifactId>reactor-extra</artifactId></dependency>3.1.人为制作超时异样-用于测试为了可能制作申请超时的异样场景,咱们给连贯超时设置为5毫秒,即:让所有申请肯定会超时。(没有任何申请能在5毫秒内实现网络连接) //认为设置申请超时工夫为5毫秒,也就是申请肯定会超时,肯定会抛出ConnectTimeoutExceptionTcpClient tcpClient = TcpClient .create() .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5); //5毫秒WebClient webClient = WebClient.builder() .baseUrl("http://jsonplaceholder.typicode.com") .clientConnector(new ReactorClientHttpConnector(HttpClient.from(tcpClient))) .build();3.2.测试retryWhen用Retry对象定义申请重试的条件,也就是retryWhen的when ...

August 26, 2020 · 1 min · jiezi

关于spring:完美解决方案雪花算法ID到前端之后精度丢失问题

最近公司的一个项目组要把以前的单体利用进行为服务拆分,表的ID主键应用Mybatis plus默认 的雪花算法来生成。 快下班的时候,小伙伴跑过来找我,:“快给我看看这问题,卡这卡了小半天了!”。连拉带拽,连哄带骗的把我拉到他的电脑前面。这位小伙伴在我看来技术不算是大牛,但教训也很丰盛了。他都卡了半天的问题,应该不是小问题,如果我一时半会搞不定,真的是耽搁我上班了,所以我很不愿意的在他的地位坐了下来。 一、景象是这样的上面我把异样的景象给大家形容一下,小伙伴建了一张表,表的主键是id BigINT,用来存储雪花算法生成的ID,嗯,这个没有问题! CREATE TABLE user( id BIGINT(20) NOT NULL COMMENT '主键ID', #其余字段省略);应用Long 类型对应数据库ID数据。嗯,也没有问题,雪花算法生成的就是一串数字,Long类型属于标准答案! @Datapublic class User { private Long id;//其余成员变量省略在后端下断点。看到数据响应以JSON响应给前端,失常 {id:1297873308628307970,//其余属性省略}最初,这条数据返回给前端,前端接管到之后,批改这条数据,后端再次接管回来。奇怪的问题呈现了:后端从新接管回来的id变成了:12978733086283000000,不再是1297873308628307970 二、剖析问题我的第一感觉是,开发小伙伴把数据给搞混了,张冠李戴了,把XXX的对象ID放到了YYY对象的ID上。所以,就依照代码从前端到后端、从后端到前端调试跟踪了一遍。 从代码的逻辑角度上没有任何问题。这时,我有点焦躁了,真的是耽搁我上班了!但动工没有回头箭,既然坐下来了就得帮他解决,不然当前这队伍怎么带?想到这我又静下心来,开始思考。 1297873308628300000 ---> 1297873308628307970这两个数长得还挺像的,仿佛是被四舍五入了。此时脑袋外面冒出一个想法,是精度失落了么?哪里能导致精度失落? 服务端都是Long类型的id,不可能失落前端是什么类型,JSON字符串转js对象,接管Long类型的是number上网查了一下Number精度是16位(雪花ID是19位的),So:JS的Number数据类型导致的精度失落。问题是找到了!小伙伴投来钦佩的眼光,5分钟就把这问题发现了。可是发现了有什么用?得解决问题啊! 三、解决问题开发小伙伴说:那我把所有的数据库表设计,id字段由Long类型改成String类型吧。我问他你有多少张表?他说100多张吧。 100多张表还有100多个实体类须要改还有各种应用到实体类的Service层要改Service等改完Controller层要改要害的是String和Long都是罕用类型,他还不敢批量替换小伙伴拿起电话打算订餐,说今晚的加班是无奈防止了。我想了想说:你最好别改,String做ID查问性能会降落,我再想想!后端A到前端B呈现精度失落,要么改前端,要么改后端,要么…… 。“哎哎,你等等先别订餐,后端A到前端B你用的什么做的序列化?” 小伙伴通知我说应用的是Jackson,这就好办了,Jackson我相熟啊! 解决思路:后端的ID(Long) ==> Jackson(Long转String) ==> 前端应用String类型的ID,前端应用js string精度就不会失落了。 那前端再把String类型的19位数字传回服务端的时候,能够用Long接管么?当然能够,这是Spring反序列化参数接管默认反对的行为。 最终计划就是:前端用String类型的雪花ID放弃精度,后端及数据库持续应用Long(BigINT)类型不影响数据库查问执行效率。 剩下的问题就是:在Spring Boot利用中,应用Jackson进行JSON序列化的时候怎么将Long类型ID转成String响应给前端。计划如下: @Configurationpublic class JacksonConfig { @Bean @Primary @ConditionalOnMissingBean(ObjectMapper.class) public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { ObjectMapper objectMapper = builder.createXmlMapper(false).build(); // 全局配置序列化返回 JSON 解决 SimpleModule simpleModule = new SimpleModule(); //JSON Long ==> String simpleModule.addSerializer(Long.class, ToStringSerializer.instance); objectMapper.registerModule(simpleModule); return objectMapper; }}小伙伴放下电话, 再次投来钦佩眼光。“走吧,一起上班!”我和小伙伴说,小伙伴一路上始终问我你是怎么学习的?我冠冕堂皇的说了一些多想多学多问之类的话。其实我心里在想:我是一个懒人,但我不能说。能躺着绝不坐着,能主动绝不手动,能打车绝不本人开车。第一次就把事件做对,才是省时省力做好的办法!这么多年的“懒”,决定了我须要去思考更多的“捷径”,思考“捷径”的过程是我一直进阶的窍门!怠惰的人是社会的生产力,而懒人是社会的创造力! ...

August 25, 2020 · 1 min · jiezi

关于spring:Spring-源码第-8-篇各种属性的解析

Spring 源码解析第 8 篇,持续。 上篇文章咱们剖析了 bean 标签的解析过程,然而次要是波及到一些简略的属性,一些冷门属性如 lookup-method 等没有和大家剖析,次要是思考到这些属性大家可能用得少,因而我上周录制了一个简略的视频,先率领小伙伴们温习了一下这些冷门属性的用法: Spring 中四个冷门属性,你可能没用过,挑战看一下! 当初对于 bean 节点的配置大家都理解了,咱们接下来就来看下残缺的解析过程。 浏览本系列后面文章,有助于更好的了解本文: Spring 源码解读打算Spring 源码第一篇开整!配置文件是怎么加载的?Spring 源码第二弹!XML 文件解析流程Spring 源码第三弹!EntityResolver 是个什么鬼?Spring 源码第四弹!深刻了解 BeanDefinition手把手教你搭建 Spring 源码剖析环境Spring 源码第六弹!松哥和大家聊聊容器的始祖 DefaultListableBeanFactorySpring 源码解读第七弹!bean 标签的解析1.解析办法回顾上篇文章咱们最终剖析到上面这个办法: @Nullablepublic AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, @Nullable BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } try { AbstractBeanDefinition bd = createBeanDefinition(className, parent); parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); parseMetaElements(ele, bd); parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); parseConstructorArgElements(ele, bd); parsePropertyElements(ele, bd); parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } catch (ClassNotFoundException ex) { error("Bean class [" + className + "] not found", ele, ex); } catch (NoClassDefFoundError err) { error("Class that bean class [" + className + "] depends on not found", ele, err); } catch (Throwable ex) { error("Unexpected failure during bean definition parsing", ele, ex); } finally { this.parseState.pop(); } return null;}parseBeanDefinitionAttributes 办法用来解析一般属性,咱们曾经在上篇文章中剖析过了,这里不再赘述,明天次要来看看其余几个办法的解析工作。 ...

August 24, 2020 · 4 min · jiezi