随机数设置及参数间引用

1.8 随机数设置及参数间引用 在Spring Boot配置文件中设置属性时,除了可以像前面示例中显示的配置属性值外,还可以使用随机值和参数间引用对属性值进行设置。下面,针对配置文件中这两种属性值的设置方式进行讲解 1.8.1随机值设置 在Spring Boot配置文件中,随机值设置使用到了Spring Boot内嵌的RandomValuePropertySource类,对一些隐秘属性值或者测试用例属性值进行随机值注入 随机值设置的语法格式为${random.xx},xx表示需要指定生成的随机数类型和范围,它可以生成随机的整数、uuid或字符串,示例代码如下 properties my.secret=${random.value} // 配置随机值 my.number=${random.int} // 配置随机整数 my.bignumber=${random.long} // 配置随机long类型数 my.uuid=${random.uuid} // 配置随机uuid类型数 my.number.less.than.ten=${random.int(10)} // 配置小于10的随机整数 my.number.in.range=${random.int[1024,65536]} // 配置范围在[1024,65536]之间的随机整数 上述代码中,使用RandomValuePropertySource类中random提供的随机数类型,分别展示了不同类型随机值的设置示例 1.8.2参数间引用 在Spring Boot配置文件中,配置文件的属性值还可以进行参数间的引用,也就是在后一个配置的属性值中直接引用先前已经定义过的属性,这样可以直接解析其中的属性值了。 使用参数间引用的好处就是,在多个具有相互关联的配置属性中,只需要对其中一处属性预先配置,其他地方都可以引用,省去了后续多处修改的麻烦 参数间引用的语法格式为${xx},xx表示先前在配置文件中已经配置过的属性名,示例代码如下 properties app.name=MyApp app.description=${app.name} is a Spring Boot application 上述参数间引用设置示例中,先设置了“app.name=MyApp”,将app.name属性的属性值设置为了MyApp;接着,在app.description属性配置中,使用${app.name}对前一个属性值进行了引用 接下来,通过一个案例来演示使用随机值设置以及参数间引用的方式进行属性设置的具体使用和效果,具体步骤如下 (1)打开Spring Boot项目resources目录下的application.properties配置文件,在该配置文件中分别通过随机值设置和参数间引用来配置两个测试属性,示例代码如: properties 随机值设置以及参数间引用配置 tom.age=${random.int[10,20]} tom.description=tom的年龄可能是${tom.age} 在上述application.properties配置文件中,先使用随机值设置了tom.age属性的属性值,该属性值设置在了[10,20]之间,随后使用参数间引用配置了tom.description属性 (2)打开\项目的测试类,在该测试类中新增字符串类型的description属性,并将配置文件中的tom.description属性进行注入,然后新增一个测试方法进行输出测试,示例代码如下 java @Value("${tom.description}") private String description; ...

June 9, 2020 · 1 min · jiezi

自定义RedisCacheManager

自定义RedisCacheManager 在项目的Redis配置类RedisConfig中,按照上一步分析的定制方法自定义名为cacheManager的Bean组件 @Bean public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { // 分别创建String和JSON格式序列化对象,对缓存数据key和value进行转换 RedisSerializer<String> strSerializer = new StringRedisSerializer(); Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class); // 解决查询缓存转换异常的问题 ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jacksonSeial.setObjectMapper(om); // 定制缓存数据序列化方式及时效 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofDays(1)) .serializeKeysWith(RedisSerializationContext.SerializationPair .fromSerializer(strSerializer)) .serializeValuesWith(RedisSerializationContext.SerializationPair .fromSerializer(jacksonSeial)) .disableCachingNullValues(); RedisCacheManager cacheManager = RedisCacheManager .builder(redisConnectionFactory).cacheDefaults(config).build(); return cacheManager; } 上述代码中,在RedisConfig配置类中使用@Bean注解注入了一个默认名称为方法名的cacheManager组件。在定义的Bean组件中,通过RedisCacheConfiguration对缓存数据的key和value分别进行了序列化方式的定制,其中缓存数据的key定制为StringRedisSerializer(即String格式),而value定制为了Jackson2JsonRedisSerializer(即JSON格式),同时还使用entryTtl(Duration.ofDays(1))方法将缓存数据有效期设置为1天 完成基于注解的Redis缓存管理器RedisCacheManager定制后,可以对该缓存管理器的效果进行测试(使用自定义序列化机制的RedisCacheManager测试时,实体类可以不用实现序列化接口) 学习让人快乐,学习更让人觉得无知!学了1个多月的《Java工程师高薪训练营》,才发现自己对每个技术点的认知都很肤浅,根本深不下去,立个Flag:每天坚持学习一小时,一周回答网上3个技术问题,把自己知道都分享出来。

June 9, 2020 · 1 min · jiezi

Redis注解默认序列化机制

Redis注解默认序列化机制 打开Spring Boot整合Redis组件提供的缓存自动配置类RedisCacheConfiguration(org.springframework.boot.autoconfigure.cache包下的),查看该类的源码信息,其核心代码如下 @Configurationclass RedisCacheConfiguration { @Bean public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory,ResourceLoader resourceLoader) { RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory) .cacheDefaults(this.determineConfiguration(resourceLoader.getClassLoader())); List<String> cacheNames = this.cacheProperties.getCacheNames(); if(!cacheNames.isEmpty()) { builder.initialCacheNames(new LinkedHashSet(cacheNames)); } return (RedisCacheManager)this.customizerInvoker.customize(builder.build()); } private org.springframework.data.redis.cache.RedisCacheConfiguration determineConfiguration(ClassLoader classLoader){ if(this.redisCacheConfiguration != null) { return this.redisCacheConfiguration; } else { Redis redisProperties = this.cacheProperties.getRedis(); org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration.defaultCacheConfig(); config = config.serializeValuesWith(SerializationPair.fromSerializer( new JdkSerializationRedisSerializer(classLoader))); ... return config; } }}从上述核心源码中可以看出,同RedisTemplate核心源码类似,RedisCacheConfiguration内部同样通过Redis连接工厂RedisConnectionFactory定义了一个缓存管理器RedisCacheManager;同时定制RedisCacheManager时,也默认使用了JdkSerializationRedisSerializer序列化方式。 如果想要使用自定义序列化方式的RedisCacheManager进行数据缓存操作,可以参考上述核心代码创建一个名为cacheManager的Bean组件,并在该组件中设置对应的序列化方式即可 注意,在Spring Boot 2.X版本中,RedisCacheManager是单独进行构建的。因此,在Spring Boot 2.X版本中,对RedisTemplate进行自定义序列化机制构建后,仍然无法对RedisCacheManager内部默认序列化机制进行覆盖(这也就解释了基 于注解的Redis缓存实现仍然会使用JDK默认序列化机制的原因),想要基于注解的Redis缓存实现也使用自定义序列化机制,需要自定义RedisCacheManager刚学了拉勾教育的《Java工程师高薪训练营》,看到刚学到的点就回答了。希望拉勾能给我推到想去的公司,目标:字节!! ...

June 9, 2020 · 1 min · jiezi

源码分析-手写mybaitspring核心功能干货好文一次学会工厂bean类代理bean注册的使用

作者:小傅哥博客:https://bugstack.cn - 汇总系列原创专题文章 沉淀、分享、成长,让自己和他人都能有所收获!?一、前言介绍一个知识点的学习过程基本分为;运行helloworld、熟练使用api、源码分析、核心专家。在分析mybaits以及mybatis-spring源码之前,我也只是简单的使用,因为它好用。但是他是怎么做的多半是凭自己的经验去分析,但始终觉得这样的感觉缺少点什么,在几次夙兴夜寐,靡有朝矣之后决定彻底的研究一下,之后在去仿照着写一版核心功能。依次来补全自己的技术栈的空缺。在现在技术知识像爆炸一样迸发,而我们多半又忙于工作业务开发。就像一个不会修车的老司机,只能一脚油门,一脚刹车的奔波。车速很快,但经不起坏,累觉不爱。好!为了解决这样问题,也为了钱程似锦(形容钱多的想家里的棉布一样),努力! 开动之前先庆祝下我的iPhone4s又活了,还是那么好用(嗯!有点卡); 二、以往章节关于mybaits & spring 源码分析以及demo功能的章节汇总,可以通过下列内容进行系统的学习,同时以下章节会有部分内容涉及到demo版本的mybaits; 源码分析 | Mybatis接口没有实现类为什么可以执行增删改查源码分析 | 像盗墓一样分析Spring是怎么初始化xml并注册bean的源码分析 | 基于jdbc实现一个Demo版的Mybatis三、一碟小菜类代理往往从最简单的内容才有抓手。先看一个接口到实现类的使用,在将这部分内容转换为代理类。 1. 定义一个 IUserDao 接口并实现这个接口类public interface IUserDao { String queryUserInfo();}public class UserDao implements IUserDao { @Override public String queryUserInfo() { return "实现类"; }}2. new() 方式实例化IUserDao userDao = new UserDao();userDao.queryUserInfo();这是最简单的也是最常用的使用方式,new 个对象。 3. proxy 方式实例化ClassLoader classLoader = Thread.currentThread().getContextClassLoader();Class<?>[] classes = {IUserDao.class};InvocationHandler handler = (proxy, method, args) -> "你被代理了 " + method.getName();IUserDao userDao = (IUserDao) Proxy.newProxyInstance(classLoader, classes, handler);String res = userDao.queryUserInfo();logger.info("测试结果:{}", res);Proxy.newProxyInstance 代理类实例化方式,对应传入类的参数即可ClassLoader,是这个类加载器,我们可以获取当前线程的类加载器InvocationHandler 是代理后实际操作方法执行的内容,在这里可以添加自己业务场景需要的逻辑,在这里我们只返回方法名测试结果: ...

June 9, 2020 · 5 min · jiezi

SpringApplication实例的初始化创建

SpringApplication实例的初始化创建 查看SpringApplication实例对象初始化创建的源码信息,核心代码具体如下 java public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) { this.sources = new LinkedHashSet(); this.bannerMode = Mode.CONSOLE; this.logStartupInfo = true; this.addCommandLineProperties = true; this.addConversionService = true; this.headless = true; this.registerShutdownHook = true; this.additionalProfiles = new HashSet(); this.isCustomEnvironment = false; this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); //把项目启动类.class设置为属性存储起来 this.primarySources = new LinkedHashSet(Arrays.asList(primarySources)); //判断当前webApplicationType应用的类型 this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 设置初始化器(Initializer),最后会调用这些初始化器 this.setInitializers(this.getSpringFactoriesInstances( ApplicationContextInitializer.class)); // 设置监听器(Listener) this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); // 用于推断并设置项目main()方法启动的主程序启动类 this.mainApplicationClass = this.deduceMainApplicationClass(); ...

June 8, 2020 · 1 min · jiezi

SpringApplication的初始化过程

SpringApplication的初始化过程主要包括4部分,具体说明如下。 (1)this.webApplicationType = WebApplicationType.deduceFromClasspath() 用于判断当前webApplicationType应用的类型。deduceFromClasspath()方法用于查看Classpath类路径下是否存在某个特征类,从而判断当前webApplicationType类型是SERVLET应用(Spring 5之前的传统MVC应用)还是REACTIVE应用(Spring 5开始出现的WebFlux交互式应用) (2)this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)) 用于SpringApplication应用的初始化器设置。在初始化器设置过程中,会使用Spring类加载器SpringFactoriesLoader从META-INF/spring.factories类路径下的META-INF下的spring.factores文件中获取所有可用的应用初始化器类ApplicationContextInitializer。 (3)this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)) 用于SpringApplication应用的监听器设置。监听器设置的过程与上一步初始化器设置的过程基本一样,也是使用SpringFactoriesLoader从META-INF/spring.factories类路径下的META-INF下的spring.factores文件中获取所有可用的监听器类ApplicationListener。 (4)this.mainApplicationClass = this.deduceMainApplicationClass() 用于推断并设置项目main()方法启动的主程序启动类 学习让人快乐,学习更让人觉得无知!学了1个多月的《Java工程师高薪训练营》,才发现自己对每个技术点的认知都很肤浅,根本深不下去,立个Flag:每天坚持学习一小时,一周回答网上3个技术问题,把自己知道都分享出来。

June 8, 2020 · 1 min · jiezi

Spring-Security-中的身份认证

原文链接:https://blog.gaoyuexiang.cn/2020/06/07/spring-security-authentication/,内容无差别。 本文介绍 Spring Security 的身份认证的内容,研究 Spring Security 自带的身份认证方式和添加自己的身份认证方式的方法。 身份认证相关组件在上一篇文章中,我们了解到了 Spring Security 会将 DelegatingFilterProxy 插入到 Servlet Filter Chain 中,然后将要过滤的请求通过 FilterChainProxy 代理给匹配的 SecurityFilterChain;这些 SecurityFilterChain 中包含着真正做安全相关工作的 Filter。 这些 Filter 中的一部分,他们的职责就是进行身份验证,比如 UsernamePasswordAuthenticationFilter;而他们中的大多数都有一个共同的父类 AbstractAuthenticationProcessingFilter。 AbstractAuthenticationProcessFilter这个类是很多身份认证的 Filter 的父类,它已经实现了 doFilter 方法,流程如下: 本文不涉及其中的 sessionStrategy 部分doFilter 已经帮我们搭好了这个流程,我们只需要关心其中的几个被调用的方法(红绿蓝三个颜色框)就可以了。 attemptAuthentication这是一个抽象方法。子类实现的时候,需要从 HttpServletRequest 中获取需要的信息,构建出一个 Authentication 实例,然后调用父类中的 AuthenticationManager.authenticate() 方法,对 Authentication 对象进行认证。 unsuccessfulAuthentication这个方法已经被实现,子类也可以选择重写。根据父类的实现,这个方法将完成一下步骤: 清理 SecurityContextHolder清除 RememberMeService 中的信息(默认使用 NullRememberMeService)调用 AuthenticationFailureHandler.onAuthenticationFailure() 方法默认使用的 AuthenticationFailureHandler 是 SimpleUrlAuthenticationFailureHandler,它的逻辑是: 如果没有配置 defaultFailureUrl (默认没有) 发送 401 响应根据配置的布尔值 forwardToDestination (默认为 false)判断 ...

June 7, 2020 · 2 min · jiezi

Spring-整体架构

概览Spring 是一个分层架构、由一系列的模块组成 Core Container核心容器,包含了 Core、Beans、Context、Expression Language 模块。 Core 和 Beans 模块是框架的基础部分、提供 IOC (控制反转)和依赖注入特性,这里的基础概念是 BeanFactory。 Core: 主要包含 Spring 框架基本的核心工具类,Spring 的其他组件都要用到这个包里的类,Core 模块是其他组件的基本核心。Beans: 包含访问配置文件、创建和管理 Bean 以及进行 IOC 操作相关的所有类。Context: 构建在 Core 和 Beans 模块基础上,提供了类似 JNDI 注册期的框架式的对象访问方法。Context 继承了 Beans 的特性,为 Spring 和行提供了大量扩展,添加了国际化,事件传播,资源加载和 Context 的透明创建的支持。ApplicationContext 接口是 Context 模块的关键。Expression Language: 提供了强大的表达式语言,用于在运行时查询和操纵对象。Data Access / Integration包含 JDBC、ORM、JMS、OXM 和 Transaction 模块。 Jdbc: 该模块提供了一个 JDBC 抽象层,它可以消除冗长的 JDBC 编码和解析数据库厂商特有的错误码。这个模块包含了 Spring 对 JDBC 数据访问进行封装的所有类。ORM: ORM 模块为流行的对象-关系映射 API ,如 JPA、Hibernate、Mybatis等,提供了一个交互层。利用 ORM 封装包,可以混合使用所有 Spring 提供的特性进行 O/R 映射。Oxm: 提供了一个对 Object / XML 映射实现对抽象层。Jms: 包含一些制造和消费消息的特性。Transaction: 支持编程性和声明性的事务管理,这些事务类必须实现特定的接口。Webweb 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。Web 层包含了 Web 模块、Web-servlet、Web-portlet。 ...

June 6, 2020 · 1 min · jiezi

Spring-获取单例流程三

读完这篇文章你将会收获到 Spring 何时将 bean 加入到第三级缓存和第一级缓存中Spring 何时回调各种 Aware 接口、BeanPostProcessor 、InitializingBean 等相关文章 Spring 获取单例流程(一)Spring 获取单例流程(二)Spring 循环依赖 (公众号内查看(同时发布无法获取到链接))概述上两篇文章 Spring 获取单例流程(一) 和 Spring 获取单例流程(二) 介绍了 getBean 前面的流程,今天最后的收尾,把后面的流程继续一起学习下 源码分析// 我依赖的大哥都好了// Create bean instance.if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { // 从三级缓存中移除这个 beanName 因为它可能被放进去了 因为放进去三级缓存可以解决 setter 的循环依赖 destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);} 如果我们要创建的 bean 是一个单例, ...

June 6, 2020 · 3 min · jiezi

Spring-循环依赖

读完这篇文章你将会收获到 Spring 循环依赖可以分为哪两种Spring 如何解决 setter 循环依赖Spring 为何是三级缓存 , 二级不行 ?Spring 为啥不能解决构造器循环依赖概述循环依赖就是循环引用,两个或以上的 bean 相互持有对方。比如说 beanA 引用 beanB , beanB 引用 beanC , beanC 引用 beanA , 它们之间的引用关系构成一个环。 Spring 如何解决循环依赖Spring 中的循环依赖包括 构造器循环依赖setter 循环依赖构造器的依赖Spring 对于构造器的依赖、无法解决。只会抛出 BeanCurrentlyInCreationException 异常。 protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } }setter 的循环依赖不管是 autowireByName 还是 autowireByType 都是属于这种。Spring 默认是能够解决这种循环依赖的,主要是通过 Spring 容器提前暴露刚完成构造器注入但未完成其他步骤的 bean 来完成的。而且只能解决 singleton 类型的循环依赖、对于 prototype 类型的是不支持的,因为 Spring 没有缓存这种类型的 bean ...

June 6, 2020 · 3 min · jiezi

Spring-获取单例流程二

读完这篇文章你将会收获到 Spring 中 prototype 类型的 bean 如何做循环依赖检测Spring 中 singleton 类型的 bean 如何做循环依赖检测前言继上一篇文章 Spring 获取单例流程(一) 我们这次继续往下分析一下后面的流程 上一篇文章中我们说到,首先我们根据 name 找到其对应的 beanName 、然后去缓存中看是否已经创建了/创建中这个对应的 bean,如果在缓存中找到了这个 bean、那么我们需要对这个 bean 可能进行一些处理,比如说用户想要的是一个普通的 bean 、但是在 Spring 缓存中找到的是一个 factoryBean、这个时候就要调用 fatoryBean 的 getObject 方法以及对应的一些前置方法以及回调等。 那么如果我们在缓存中找不到这个 bean 那么流程又是怎么样?这个就是这篇文章要跟大家一起分享的 源码分析if (sharedInstance != null && args == null) { // 这里被我删除了一些spring 的log // 处理一下 factory bean 的情况、包括从 factory beans 的缓存中获取、或者重新调用 factory bean 的 get bean 方法 包括一些回调 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);} else { // 从 上面的 getSingleton 拿不到对象的bean 、说明这个bean的scope 要么不是 singleton 要这个bean是singleton 但是没有初始化一句 // 因为 Spring 只解决单例模式下得循环依赖,在原型模式下如果存在循环依赖则会抛出异常 // 这里的循环依赖检查使用的 是 threadLocal 因为 prototype 类型的只是 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // 如果容器中没有找到,则从父类容器中加载 BeanFactory parentBeanFactory = getParentBeanFactory(); // parentBeanFactory 不为空且 beanDefinitionMap 中不存该 name 的 BeanDefinition if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // Not found -> check parent. // 这里只是找出他的真正的beanName、并没有去掉 factory bean 的前缀 String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null) { // Delegation to parent with explicit args. return (T) parentBeanFactory.getBean(nameToLookup, args); } else if (requiredType != null) { // No args -> delegate to standard getBean method. return parentBeanFactory.getBean(nameToLookup, requiredType); } else { return (T) parentBeanFactory.getBean(nameToLookup); } } ....... ....... ........}第一步就是判断这个是否是一个 prototype 类型的 bean,如果是并且正在创建中、那么就抛出一个循环依赖的异常 ...

June 6, 2020 · 4 min · jiezi

Spring-容器的初始化

读完这篇文章你将会收获到 了解到 Spring 容器初始化流程ThreadLocal 在 Spring 中的最佳实践面试中回答 Spring 容器初始化流程引言我们先从一个简单常见的代码入手分析 <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "https://www.springframework.org/dtd/spring-beans-2.0.dtd"><beans> <bean class="com.demo.data.Person"> <description> 微信搜一搜:CoderLi(不妨关注➕一下?这次一定?) </description> </bean></beans>public static void main(String[] args) { Resource resource = new ClassPathResource("coderLi.xml"); DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory); xmlBeanDefinitionReader.loadBeanDefinitions(resource); }上面这段 Java 代码主要做了 资源的获取(定位)创建一个 beanFactory根据 beanFactory (实现了 BeanDefinitionRegistry 接口) 创建一个 beanDefinitionReader装载资源并 registry 资源里面的 beanDefinition所以总体而言就是资源的加载、加载、注册三个步骤 对于资源的加载可以看看我另一篇文章 Spring-资源加载(源码分析)加载的过程则是将 Resource 对象转为一系列的 BeanDefinition 对象注册则是将 BeanDefinition 注入到 BeanDefinitionRegistry 中组件介绍在分析源码流程之前我们一起先对一些重要的组件混个眼熟 ...

June 6, 2020 · 6 min · jiezi

SpringAliasRegistry

使用Spring 的时候我们可以很容易的为某个bean 配置一个或多个别名 <bean id="app:dataSource" class="..."> <alias name="app:dataSoure" alias="user:dataSoure"/> <alias name="app:dataSoure" alias="device:dataSoure"/> </bean> 或者: 直接使用bean标签的name属性,就是别名 <bean id="aaa",name="bbb,ccc,ddd"/> 使用 @Bean 注解的时候 @Bean(value = {"aaa", "bbb", "ccc"})那么 除了第一个是这个 beanName(bean id) 之外、其他的都是 alias public interface AliasRegistry { /** * 为这个 name 注册一个 alias */ void registerAlias(String name, String alias); /** * 从注册表中移除这个alias对应的关系 */ void removeAlias(String alias); /** * 给定的这个 name是否是一个 别名 */ boolean isAlias(String name); /** * 根据这个 bean name 获取所有他的别名 */ String[] getAliases(String name);}AliasRegistry 其中的一个实现类 SimpleAliasRegistry ...

June 6, 2020 · 2 min · jiezi

Spring资源加载

在 Java 中,将不同来源的资源抽象成 URL ,通过注册不同的 handler ( URLStreamHandler ) 来处理不同来源的资源的读取逻辑。 然而 URL 没有默认定义相对 Classpath 或 ServletContext 等资源的 handler ,虽然可以注册自己的 URLStreamHandler 来解析特定的 URL 前缀(协议)。但是 URL 也没有提供基本的方法、如检查当前资源是否存在,检查资源是否存在等方法。 URL: 我可以加载各种的资源.......XXXSpring: 你是个好人 Spring 实现了自己的资源加载策略 职能划分清楚。资源的定义和资源的加载有明确的界限统一的抽象,统一的资源定义和资源加载策略。统一资源org.springframework.core.io.Resource 接口抽象了所有 Spring 内部使用到的底层资源,如 File、URL、Classpath。 public interface Resource extends InputStreamSource { ....... .......}而 org.springframework.core.io.InputStreamSource 封装任何能返回 InputStream 的类、如 File、Classpath 下的资源和 ByteArray,该接口只有一个方法 getInputStream public interface InputStreamSource { /** * 表示任意形式的资源都可以被转换成输入流、最好每一次调用这个方法的时候都是返回一个新的InputStream * 看子类{@link FileSystemResource}符合这个要求 */ InputStream getInputStream() throws IOException;}Resource 接口提供了比 URL 更加多和便捷的方法 ...

June 6, 2020 · 3 min · jiezi

applicationproperties配置文件

1.5.1 application.properties配置文件使用Spring Initializr方式构建Spring Boot项目时,会在resource目录下自动生成一个空的application.properties文件,Spring Boot项目启动时会自动加载application.properties文件。我们可以在application.properties文件中定义Spring Boot项目的相关属性,当然,这些相关属性可以是系统属性、环境变量、命令参数等信息,也可以是自定义配置文件名称和位置 server.port=8081 spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.config.additional-location= spring.config.location= spring.config.name=application 1234567891011接下来,通过一个案例对Spring Boot项目中application.properties配置文件的具体使用进行讲解演示:预先准备了两个实体类文件,后续会演示将application.properties配置文件中的自定义配置属性注入到Person实体类的对应属性中(1)先在项目的com.lagou包下创建一个pojo包,并在该包下创建两个实体类Pet和Person public class Pet { private String type; private String name; // 省略属性getXX()和setXX()方法 // 省略toString()方法 }1234567891011121314151617181920 @Component //用于将Person类作为Bean注入到Spring容器中 @ConfigurationProperties(prefix ="person") //将配置文件中以person开头的属性注入到该类中 public class Person { private int id; //id private String name; //名称 private List hobby; //爱好 private String[] family; //家庭成员 private Map map; private Pet pet; //宠物 // 省略属性getXX()和setXX()方法 // 省略toString()方法 }1234567891011121314151617181920212223242526272829303132@ConfigurationProperties(prefix =“person”)注解的作用是将配置文件中以person开头的属性值通过setXX()方法注入到实体类对应属性中@Component注解的作用是将当前注入属性值的Person类对象作为Bean组件放到Spring容器中,只有这样才能被@ConfigurationProperties注解进行赋值(2)打开项目的resources目录下的application.properties配置文件,在该配置文件中编写需要对Person类设置的配置属性编写application.properties配置文件时,由于要配置的Person对象属性是我们自定义的,Spring Boot无法自动识别,所以不会有任何书写提示。在实际开发中,为了出现代码提示的效果来方便配置,在使用@ConfigurationProperties注解进行配置文件属性值注入时,可以在pom.xml文件中添加一个Spring Boot提供的配置处理器依赖: ...

June 5, 2020 · 1 min · jiezi

完成数据的页面展示

完成数据的页面展示 1. 创建Spring Boot项目,引入Thymeleaf依赖 <img src="./images/image-20191230160651703.png" alt="image-20191230160651703" /> 2. 编写配置文件 打开application.properties全局配置文件,在该文件中对Thymeleaf模板页面的数据缓存进行设置 properties # thymeleaf页面缓存设置(默认为true),开发中方便调试应设置为false,上线稳定后应保持默认true spring.thymeleaf.cache=false 使用“spring.thymeleaf.cache=false”将Thymeleaf默认开启的缓存设置为了false,用来关闭模板页面缓存 3. 创建web控制类 在项目中创建名为com.lagou.controller的包,并在该包下创建一个用于前端模板页面动态数据替换效果测试的访问实体类LoginController ```java @Controller public class LoginController { /** * 获取并封装当前年份跳转到登录页login.html      */ @RequestMapping("/toLoginPage") public String toLoginPage(Model model){ model.addAttribute("currentYear", Calendar.getInstance().get(Calendar.YEAR)); return "login"; } ``` toLoginPage()方法用于向登录页面login.html跳转,同时携带了当前年份信息currentYear。 4.创建模板页面并引入静态资源文件 在“classpath:/templates/”目录下引入一个用户登录的模板页面login.html ```html <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1,shrink-to-fit=no"> <title>用户登录界面</title> <link th:href="@{/login/css/bootstrap.min.css}" rel="stylesheet"> <link th:href="@{/login/css/signin.css}" rel="stylesheet"> </head> <body class="text-center"> <!--  用户登录form表单 --> <form class="form-signin"> ...

June 5, 2020 · 1 min · jiezi

编写Web访问层Controller文件

编写Web访问层Controller文件 java @RestController @RequestMapping("api") //窄化请求路径 public class ApiCommentController { @Autowired private ApiCommentService commentService; @RequestMapping(value = "/findCommentById") public Comment findCommentById(Integer id){ Comment comment = commentService.findCommentById(id); return comment; } @RequestMapping(value = "/updateComment") public void updateComment(Comment comment){ Comment comment2 = commentService.findCommentById(comment.getId()); comment.setAuthor(comment.getAuthor()); commentService.updateComment(comment); } @RequestMapping(value = "/deleteComment") public void deleteComment(int id){ commentService.deleteComment(id); } } * 基于API的Redis缓存实现的相关配置。基于API的Redis缓存实现不需要@EnableCaching注解开启基于注解的缓存支持,所以这里可以选择将添加在项目启动类上的@EnableCaching进行删除或者注释 这些内容,是从拉勾教育的《Java工程师高薪训练营》里学到的,课程内容非常全面,还有拉勾的内推大厂服务,推荐你也看看。

June 5, 2020 · 1 min · jiezi

编写多语言国际化配置文件

编写多语言国际化配置文件 在项目的类路径resources下创建名称为i18n的文件夹,并在该文件夹中根据需要编写对应的多语言国际化文件login.properties、login_zh_CN.properties和login_en_US.properties文件 login.properties properties login.tip=请登录 login.username=用户名 login.password=密码 login.rememberme=记住我 login.button=登录 login_zh_CN.properties properties login.tip=请登录 login.username=用户名 login.password=密码 login.rememberme=记住我 login.button=登录 login_en_US.properties properties login.tip=Please sign in login.username=Username login.password=Password login.rememberme=Remember me login.button=Login login.properties为自定义默认语言配置文件,login_zh_CN.properties为自定义中文国际化文件,login_en_US.properties为自定义英文国际化文件 需要说明的是,Spring Boot默认识别的语言配置文件为类路径resources下的messages.properties;其他语言国际化文件的名称必须严格按照“文件前缀名_语言代码_国家代码.properties”的形式命名 本示例中,在项目类路径resources下自定义了一个i18n包用于统一配置管理多语言配置文件,并将项目默认语言配置文件名自定义为login.properties,因此,后续还必须在项目全局配置文件中进行国际化文件基础名配置,才能引用自定义国际化文件 这些内容,是从拉勾教育的《Java工程师高薪训练营》里学到的,课程内容非常全面,还有拉勾的内推大厂服务,推荐你也看看。

June 5, 2020 · 1 min · jiezi

Spring-Boot-新手指南101

Spring Boot 新手指南101这篇文适合谁?有一定Java基础,且想进一步了解如何利用Java Spring Boot 搭建后台服务的你们。内容将分为两部分 Spring Boot 基础,项目创建,API定义,内存数据库搭建,实现基本的Restful操作增删查改Spring Boot进阶,连接Postgress 数据库Spring Boot基础基础数据层 数据持久: Data Access Layer服务层 业务逻辑: Service LayerAPI层 请求交互: API Layer 以数据层为例,我们不需要提前选定用哪个服务器(不论是Postgress 还是MongoDB),依赖注入框架的好处是,我们可以先定义好接口(Interface),之后根据实际情况调整具体的实现(Implementation)。 创建项目打开浏览器,去这个Spring 官方网站 https://start.spring.io/ 选择一个模板 接下来我们会利用如下的配置: MavenJava 8Spring Boot 2.3.0Name: demoPackaging: JarDependency: Spring Web (Build web, including RESTful, applications using Spring MVC. Uses Apache Tomcat as the default embedded container.)完整的项目依赖文件在 pom.xml 第一次运行打开刚刚下载的文件:demo.zip, 解压后用打开。笔者选用的是IntelliJ IDEA。 项目文件组织结构 src pom.xml main java DemoApplication 等待Spring下载好所有依赖后,打开 DemoApplication class, 找到main(), 点击 run ...

June 5, 2020 · 1 min · jiezi

Spring优缺点分析

1.2.1 spring优缺点分析优点: spring是Java企业版(Java Enterprise Edition,JEE,也称J2EE)的轻量级代替品。无需开发重量级的Enterprise JavaBean(EJB),Spring为企业级Java开发提供了一种相对简单的方法,通过依赖注入和面向切面编程,用简单 的Java对象(Plain Old Java Object,POJO)实现了EJB的功能 缺点: 虽然Spring的组件代码是轻量级的,但它的配置却是重量级的。一开始,Spring用XML配置,而且是很多XML配 置。Spring 2.5引入了基于注解的组件扫描,这消除了大量针对应用程序自身组件的显式XML配置。Spring 3.0引入 了基于Java的配置,这是一种类型安全的可重构配置方式,可以代替XML。 所有这些配置都代表了开发时的损耗。因为在思考Spring特性配置和解决业务问题之间需要进行思维切换,所以编 写配置挤占了编写应用程序逻辑的时间。和所有框架一样,Spring实用,但与此同时它要求的回报也不少。 除此之外,项目的依赖管理也是一件耗时耗力的事情。在环境搭建时,需要分析要导入哪些库的坐标,而且还需要分析导入与之有依赖关系的其他库的坐标,一旦选错了依赖的版本,随之而来的不兼容问题就会严重阻碍项目的开发进度 。 学习让人快乐,学习更让人觉得无知!学了1个多月的《Java工程师高薪训练营》,才发现自己对每个技术点的认知都很肤浅,根本深不下去,立个Flag:每天坚持学习一小时,一周回答网上3个技术问题,把自己知道都分享出来。

June 5, 2020 · 1 min · jiezi

编译Spring520源码

下载 spring-framework-5.2.0.RELEASE.zip https://github.com/spring-projects/spring-framework/releases下载gradle 5.6.3 按照说明配置环境变量 https://gradle.org/install/解压zip、查看根目录下的 import-into-idea.md 执行脚本 (windows 系统) .\gradlew.bat :spring-oxm:compileTestJava成功之后、使用IDEA打开 成功打开项目之后,我们将 spring-aspects 模块unload 然后我们可以新建一个我们自己使用的模块 打开 project structuer 然后我们为这个新建的模块引入一些我们需要用到的 Spring 的一些 jar 包 在我们的新模块中使用 Spring 的时候、可能会出现下面的问题 java: cannot find symbol symbol: variable CoroutinesUtils location: class org.springframework.core.ReactiveAdapterRegistry.CoroutinesRegistrar Error:(348, 51) java: cannot find symbol symbol: variable CoroutinesUtils location: class org.springframework.core.ReactiveAdapterRegistry.CoroutinesRegistrar解决办法 把这个 spring-core/kotlin-coroutines/build/libs/kotlin-coroutines-5.2.0.RELEASE.jar 引入到项目中即可 第二个可能出现的问题 Exception in thread "main" java.lang.NoClassDefFoundError: org/springframework/cglib/core/NamingPolicy 将 spring core 中的 build/lib 的 spring-cglib-repack-3.3.0.jar 和 spring-objenesis-repack-3.0.1.jar 引入到新增的模块中 ...

June 3, 2020 · 1 min · jiezi

使用-Spring-API-实现邮件发送-乐字节java乐字节架构

详细Spring如何进行邮件发送本文由乐字节Java架构课程独家赞助播出 环境准备创建 Maven 项目,在 pom.xml 文件中添加依赖 <!-- spring核心 jar 依赖 --><dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.4.RELEASE</version></dependency><!--spring 上下文环境 支持--><dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>5.2.4.RELEASE</version></dependency><dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.2.4.RELEASE</version> <scope>test</scope></dependency><!-- Java Mail坐标依赖 --><dependency> <groupId>com.sun.mail</groupId> <artifactId>javax.mail</artifactId> <version>1.6.2</version></dependency>配置邮件发送 bean在 spring.xml 配置文件中设置邮件发送对应的bean标签 <?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 http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 开启自动化扫描 --> <context:component-scan base-package="com.xxxx"/> <!-- 邮件发送器(提供了邮件发送接口、透明创建Java Mail的MimeMessage、及邮件发送的配置) --> <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"> <property name="host" value="smtp.163.com" /> <property name="port" value="25" /> <property name="defaultEncoding" value="utf-8"></property> <property name="username" value="用户名"></property> <property name="password" value="密码"></property> </bean> <!-- 普通文本邮件对象 --> <bean id="templateMessage" class="org.springframework.mail.SimpleMailMessage"> <property name="from" value="发件人的邮箱地址" /> <property name="subject" value="spring_mail" /> </bean></beans>定义接口与实现类定义接口 ...

June 2, 2020 · 2 min · jiezi

spring中使用mybatis实现批量插入

有3种实现方式:foreach,spring事务,以及ExecutorType.BATCH. 1. foreach方式这种方式实际是对SQL语句进行拼接,生成一个长长的SQL,对很多变量进行绑定。如果数据量不大(1000个以内),可以用这种方式。如果数据量太大,可能数据库会报错。 定义接口public interface StudentMapper05 { public void insertStudent(List<Student> studentList);}定义mapper适用于Oracle数据库 <insert id="insertStudent"> BEGIN <foreach collection="list" item="student" index="index" separator=""> INSERT INTO test_student(ID, NAME, BRANCH, PERCENTAGE, PHONE, EMAIL) VALUES (SEQ_ID.nextval, #{student.name}, #{student.branch}, #{student.percentage}, #{student.phone}, #{student.email}); </foreach> END;</insert>这个mapper的含义,就是把上送的studentList拼接成一个长SQL,拼成的SQL类似: BEGININSERT INTO test_student(ID, NAME, BRANCH, PERCENTAGE, PHONE, EMAIL) VALUES (SEQ_ID.nextval, ?, ?, ?, ?, ?);INSERT INTO test_student(ID, NAME, BRANCH, PERCENTAGE, PHONE, EMAIL) VALUES (SEQ_ID.nextval, ?, ?, ?, ?, ?);INSERT INTO test_student(ID, NAME, BRANCH, PERCENTAGE, PHONE, EMAIL) VALUES (SEQ_ID.nextval, ?, ?, ?, ?, ?);...END;studentList有几个,就会生成多少个insert语句拼接到一起,每个?都会进行变量绑定,所以当studentList中数据量较多时,生成的SQL会很长,导致数据库执行报错。 ...

June 1, 2020 · 3 min · jiezi

Spring-Security-Servlet-概览

Spring Security 是 Spring 框架中用于实现 Security 相关需求的项目。我们可以通过使用这个框架来实现项目中的安全需求。 今天这篇文章将会讨论 Spring Security Servlet 是如何工作的。 之所以将内容限定到 Servlet,是因为现在 Spring Security 已经开始支持 Reactive Web Server,因为底层的技术不同,当然需要分开讨论。 Spring Security 在哪里生效我们知道,在 Servlet 中,一次请求会经过这样的阶段: client -> servlet container -> filter -> servlet 而 Spring MVC 虽然引入了一些其他概念,但整体流程差别不大: Spring Security 则是通过实现了 Filter 来实现的 Security 功能。这样一来,只要使用了 Servlet Container,就可以使用 Spring Security,不需要关心有没有使用 Spring Web 或别的 Spring 项目。 DelegatingFilterProxy这是 Spring Security 实现的一个 Servlet Filter。它被加入到 Servlet Filter Chain 中,将 filter 的任务桥接给 Spring Context 管理的 bean。 ...

May 31, 2020 · 2 min · jiezi

从单体架构到分布式架构一万丈高楼平地起环境准备

【从单体架构到分布式架构】本系列文章希望用浅显直白的语言介绍架构发展过程中遇到的各种问题,以及对应的解决方案和优缺点。在正式学习之前,开发环境需要做好哪些准备呢?我们为什么要选择使用 Spring Boot 呢?Spring Boot 和 Spring 是两个截然不同的框架么?1. 环境准备本课程在学习过程中,会有大量的代码配合讲解,所以在正式学习之前,你需要做好以下准备。 1.1 JDK必备;本课程所有代码基于 JDK 1.8 编写。 C:\>java -versionjava version "1.8.0_171"Java(TM) SE Runtime Environment (build 1.8.0_171-b11)Java HotSpot(TM) 64-Bit Server VM (build 25.171-b11, mixed mode)1.2 Maven必备;本课程所有代码基于 Maven 构建;如果你在电脑上安装好了 Maevn,建议把 Maven 仓库的地址修改成一个国内的网站地址。 C:\>mvn -vC:\Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-11T00:41:47+08:00)Maven home: D:\Program Files\apache-maven-3.3.9\bin\..Java version: 1.8.0_171, vendor: Oracle CorporationJava home: D:\Program Files\Java\jdk1.8.0_171\jreDefault locale: zh_CN, platform encoding: GBKOS name: "windows 8.1", version: "6.3", arch: "amd64", family: "dos"1.3 IDE必备;选择一个你熟悉的 IDE,我使用的是 Eclipse,这里要注意,有些 IDE 需要进行一些 Maven 环境变量的配置。 ...

May 31, 2020 · 3 min · jiezi

Thymeleaf货币转换

概述本文,将介绍如何使用页面组件Thymeleaf对货币进行自动转换 Maven依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> <version>2.3.0.RELEASE</version></dependency>创建thymeleaf页面和Controller在resources/templates/下创建页面currencies.html <!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"><head> <meta charset="UTF-8"> <title>Currency Format</title></head><body><h3 th:text="${#numbers.formatCurrency(param.amount)}"></h3></body></html>创建CurrencyController.java package com.deepincoding.currencyformat;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestParam;@Controllerpublic class CurrencyController { @GetMapping("/currency") public String current(@RequestParam(value = "amount") String amount){ return "currency"; }}我们需要根据浏览器的区域来转换货币。使用Accept-Language表示用户的区域.在Chrome浏览器里可以设置。 启动应用后,在浏览器里输入 http://localhost:8080/currency?amount=1000000.01 返回的结果是:¥1,000,000.01 如果把浏览的语言设置为English (United States) 返回的结果是: $1,000,000.01 列表或数组我们也可以转换一个列表或数组.修改Controller如下: package com.deepincoding.currencyformat;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestParam;import java.util.List;@Controllerpublic class CurrencyController { @GetMapping("/currency") public String current(@RequestParam(value = "amount") String amount, @RequestParam(value = "amountList") List amountList){ return "currency"; }}修改页面如下: ...

May 30, 2020 · 1 min · jiezi

修炼内功springframework-6-Spring-AOP的其他实现方式

本文已收录【修炼内功】跃迁之路 在Spring AOP是如何代理的一文中介绍了Spring AOP的原理,了解到其通过JDK Proxy及CGLIB生成代理类来实现目标方法的切面(织入),这里有一个比较重要的概念 - 织入(Weaving),本篇就来探讨 什么是织入?织入有哪些类型以及实现手段?Spring分别是如何支持的?什么是织入织入为英文Weaving的直译,可字面理解为将额外代码插入目标代码逻辑中,实现对目标逻辑的增强、监控等,将不同的关注点进行解耦 织入的手段有很多种,不同的手段也对应不同的织入时机 Compile - Time Weaving (CTW) 编译期织入 在源码编译阶段,修改/新增源码,生成预期内的字节码文件 如AspectJ、Lombok、MapStruct等 Lombok、MapStruct等使用了 Pluggable Annotation Processing API 技术实现对目标代码的修改/新增AspectJ则直接使用了acj编译器 Load - Time - Weaving (LTW) 装载期织入 在Class文件的装载期,对将要装载的字节码文件进行修改,生成新的字节码进行替换 如AspectJ、Java Instrumentation等 Java Instrumentation只提供了字节码替换/重装载的能力,字节码文件的修改还需要借助外部框架,如javassist、asm等javassist的使用可以参考 Introduction to Javassist Run - Time - Weaving (RTW)运行时织入 在程序运行阶段,利用代理或者Copy目标逻辑的方式,生成新的Class并加载 如AspectJ、JDK Proxy、CGLIB等 在Spring AOP是如何代理的一文中所介绍的Spring AOP既是运行时织入 以javassist为例,Copy目标逻辑并增强(统计接口耗时),生成新的Class 该示例可应用到 装载期织入(使用新的Class替换目标Class)或 运行时织入(直接使用新的Class) // 目标代码逻辑public interface Animal { default String barkVoice() { return "bark bark"; }}public class Dog implements Animal { private final Random r = new Random(); @Override @Statistics("doggie") public String barkVoice() { try { Thread.sleep(Math.abs(r.nextInt()) % 3000); } catch (InterruptedException e) { e.printStackTrace(); } return "汪~汪~"; }}// 使用javassist,在目标代码基础上添加耗时统计逻辑,生成新的class并加载ClassPool classPool = ClassPool.getDefault();// Copy目标字节码CtClass dogClass = classPool.get(Dog.class.getName());// 设置新的类名dogClass.setName("proxy.Doggie");// 获取目标方法,并在其基础上增强CtMethod barkVoice = dogClass.getDeclaredMethod("barkVoice");barkVoice.addLocalVariable("startTime", CtClass.longType);barkVoice.insertBefore("startTime = System.currentTimeMillis();");barkVoice.insertAfter("System.out.println(\"The Dog bark in \" + (System.currentTimeMillis() - startTime) + \"ms\");");// 生成新的class (由于module机制的引入,在JDK9之后已不建议使用该方法)Class<?> doggieClass = dogClass.toClass();// 使用新的class创建对象Animal doggie = (Animal)doggieClass.getDeclaredConstructor().newInstance();// 输出 // > The Dog bark in 2453ms// > 汪~汪~System.out.println(doggie.barkVoice());JDK中的Load-Time WeavingJVM提供了两种agent包加载能力:static agent load、dynamic agent load,可分别在启动时(main函数运行之前)、运行时(main函数运行之后)加载agent包,并执行内部逻辑 ...

May 30, 2020 · 4 min · jiezi

Spring-邮件发送出现bug出现Bug以及解决方案乐字节

详细Spring如何进行邮件发送本文由乐字节Java架构课程独家赞助播出Spring 邮件发送主要内容 JavaMail 概述 JavaMail,顾名思义,提供给开发者处理电子邮件相关的编程接口。JavaMail 是由 Sun 定义的一套收发电子邮件的 API,它可以方便地执行一些常用的邮件传输,不同的厂商可以提供自己的实现类。但它并没有包含在 JDK 中,而是作为 JavaEE 的一部分。 厂商所提供的 JavaMail 服务程序可以有选择地实现某些邮件协议,常见的邮件协议包括: SMTP:简单邮件传输协议,用于发送电子邮件的传输协议;POP3:用于接收电子邮件的标准协议;IMAP:互联网消息协议,是 POP3 的替代协议。 这三种协议都有对应 SSL 加密传输的协议,分别是 SMTPS,POP3S 和 IMAPS。除 JavaMail 服务提供程序之外, JavaMail 还需要 JAF(JavaBeans Activation Framework)来处理不是纯文本的邮件内容,这包括 MIME(多用途互联网邮件扩展)、URL 页面和文件附件等内容。另外,JavaMail 依赖 JAF(JavaBeans Activation Framework),JAF 在 Java6 之后已经合并到 JDK 中,而 JDK5 之前需要另外下载 JAF 的类库。 协议介绍 在研究 JavaMail API 的细则之前,首先需要对于 API 用到的协议有个认识。对于 java mail 来说用到的协议有常见的几种: SMTP、POP、IMAP、MIME SMTP 简单邮件传输协议(Simple Mail Transfer Protocol,SMTP)由 RFC 821 定义。它定义了发送电子邮件的机制。在 JavaMail API 环境中,您基于 JavaMail 的程序将和您的公司或因特网服务供应商的(Internet ServiceProvider's,ISP's)SMTP 服务器通信。SMTP 服务器会中转消息给接收方 SMTP 服务器以便最终让用户经由 POP 或 IMAP 获得。 ...

May 29, 2020 · 2 min · jiezi

超详细4小时开发一个SpringBootvue前后端分离博客项目

作者:吕一明项目代码:https://github.com/MarkerHub/... 项目视频:https://www.bilibili.com/vide... 转载请保留此引用,感谢! 前后端分离项目文章总体分为2大部分,Java后端接口和vue前端页面,比较长,因为不想分开发布,真正想你4小时学会,哈哈。 先看效果: 不多说,开始敲代码。 Java后端接口开发1、前言从零开始搭建一个项目骨架,最好选择合适,熟悉的技术,并且在未来易拓展,适合微服务化体系等。所以一般以Springboot作为我们的框架基础,这是离不开的了。 然后数据层,我们常用的是Mybatis,易上手,方便维护。但是单表操作比较困难,特别是添加字段或减少字段的时候,比较繁琐,所以这里我推荐使用Mybatis Plus(https://mp.baomidou.com/),为简化开发而生,只需简单配置,即可快速进行 CRUD 操作,从而节省大量时间。 作为一个项目骨架,权限也是我们不能忽略的,Shiro配置简单,使用也简单,所以使用Shiro作为我们的的权限。 考虑到项目可能需要部署多台,这时候我们的会话等信息需要共享,Redis是现在主流的缓存中间件,也适合我们的项目。 然后因为前后端分离,所以我们使用jwt作为我们用户身份凭证。 ok,我们现在就开始搭建我们的项目脚手架! 技术栈: SpringBootmybatis plusshirolombokredishibernate validatiorjwt导图:https://www.markerhub.com/map/131 2、新建Springboot项目这里,我们使用IDEA来开发我们项目,新建步骤比较简单,我们就不截图了。 开发工具与环境: ideamysqljdk 8maven3.3.9新建好的项目结构如下,SpringBoot版本使用的目前最新的2.2.6.RELEASE版本 pom的jar包导入如下: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional></dependency><dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional></dependency>devtools:项目的热加载重启插件lombok:简化代码的工具3、整合mybatis plus接下来,我们来整合mybatis plus,让项目能完成基本的增删改查操作。步骤很简单:可以去官网看看:https://mp.baomidou.com/guide... 第一步:导入jar包 pom中导入mybatis plus的jar包,因为后面会涉及到代码生成,所以我们还需要导入页面模板引擎,这里我们用的是freemarker。 <!--mp--><dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.2.0</version></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId></dependency><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope></dependency><!--mp代码生成器--><dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.2.0</version></dependency>第二步:然后去写配置文件 # DataSource Configspring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/vueblog?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: adminmybatis-plus: mapper-locations: classpath*:/mapper/**Mapper.xml上面除了配置数据库的信息,还配置了myabtis plus的mapper的xml文件的扫描路径,这一步不要忘记了。第三步:开启mapper接口扫描,添加分页插件 ...

May 28, 2020 · 15 min · jiezi

SpringSpringMVCSpringBootSpringCloud有什么区别和联系

简单介绍Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。Spring使你能够编写更干净、更可管理、并且更易于测试的代码。 Spring MVC是Spring的一个模块,一个web框架。通过Dispatcher Servlet, ModelAndView 和 View Resolver,开发web应用变得很容易。主要针对的是网站应用程序或者服务开发——URL路由、Session、模板引擎、静态Web资源等等。 Spring配置复杂,繁琐,所以推出了Spring boot,约定优于配置,简化了spring的配置流程。 Spring Cloud构建于Spring Boot之上,是一个关注全局的服务治理框架。 Spring和SpringMVC: Spring是一个一站式的轻量级的java开发框架,核心是控制反转(IOC)和面向切面(AOP),针对于开发的WEB层(springMvc)、业务层(Ioc)、持久层(jdbcTemplate)等都提供了多种配置解决方案; SpringMVC是Spring基础之上的一个MVC框架,主要处理web开发的路径映射和视图渲染,属于Spring框架中WEB层开发的一部分; SpringMVC和SpringBoot: SpringMVC属于一个企业WEB开发的MVC框架,涵盖面包括前端视图开发、文件配置、后台接口逻辑开发等,XML、config等配置相对比较繁琐复杂; SpringBoot框架相对于SpringMVC框架来说,更专注于开发微服务后台接口,不开发前端视图; SpringBoot和SpringCloud: SpringBoot使用了默认大于配置的理念,集成了快速开发的Spring多个插件,同时自动过滤不需要配置的多余的插件,简化了项目的开发配置流程,一定程度上取消xml配置,是一套快速配置开发的脚手架,能快速开发单个微服务; SpringCloud大部分的功能插件都是基于SpringBoot去实现的,SpringCloud关注于全局的微服务整合和管理,将多个SpringBoot单体微服务进行整合以及管理;SpringCloud依赖于SpringBoot开发,而SpringBoot可以独立开发; 总结下来:Spring是核心,提供了基础功能;Spring MVC 是基于Spring的一个 MVC 框架 ;Spring Boot 是为简化Spring配置的快速开发整合包;Spring Cloud是构建在Spring Boot之上的服务治理框架。

May 25, 2020 · 1 min · jiezi