spring获取已实例化IOC容器中的bean(转)

Bean工厂(com.springframework.beans.factory.BeanFactory)是Spring框架最核心的接口,它提供了高级IoC的配置机制。BeanFactory使管理不同类型的Java对象成为可能,应用上下文(com.springframework.context.ApplicationContext)建立在BeanFactory基础之上,提供了更多面向应用的功能,它提供了国际化支持和框架事件体系,更易于创建实际应用。我们一般称BeanFactory为IoC容器,而称ApplicationContext为应用上下文。但有时为了行文方便,我们也将ApplicationContext称为Spring容器。 对于两者的用途,我们可以进行简单划分:BeanFactory是Spring框架的基础设施,面向Spring本身;ApplicationContext面向使用Spring框架的开发者,几乎所有的应用场合我们都直接使用ApplicationContext而非底层的BeanFactory。 ApplicationContext的初始化和BeanFactory有一个重大的区别:BeanFactory在初始化容器时,并未实例化Bean,直到第一次访问某个Bean时才实例目标Bean;而ApplicationContext则在初始化应用上下文时就实例化所有单实例的Bean。因此ApplicationContext的初始化时间会比BeanFactory稍长一些 要获取XML中配置的Bean,最关键的是获取.springframework.context.ApplicationContext,以下是总结的几种方法 方法一:在初始化时保存ApplicationContext对象方法二:通过Spring提供的utils类获取ApplicationContext对象方法三:继承自抽象类ApplicationObjectSupport方法四:继承自抽象类WebApplicationObjectSupport方法五:实现接口ApplicationContextAware方法六:通过Spring提供的ContextLoader 方法一:在初始化时保存ApplicationContext对象 说明:这种方式适用于采用Spring框架的独立应用程序,需要程序通过配置文件手工初始化Spring的情况。说明:这种方式适用于采用Spring框架的独立应用程序,需要程序通过配置文件手工初始化Spring的情况。 方法二:通过Spring提供的工具类获取ApplicationContext对象 说明:这种方式适合于采用Spring框架的B/S系统,通过ServletContext对象获取ApplicationContext对象,然后在通过它获取需要的类实例。上面两个工具方式的区别是,前者在获取失败时抛出异常,后者返回null。 方法三:继承自抽象类ApplicationObjectSupport 说明:抽象类ApplicationObjectSupport提供getApplicationContext()方法,可以方便的获取ApplicationContext。 Spring初始化时,会通过该抽象类的setApplicationContext(ApplicationContext context)方法将ApplicationContext 对象注入。 方法四:继承自抽象类WebApplicationObjectSupport 说明:类似上面方法,调用getWebApplicationContext()获取WebApplicationContext 方法五:实现接口ApplicationContextAware(推荐) 说明:实现该接口的setApplicationContext(ApplicationContext context)方法,并保存ApplicationContext 对象。Spring初始化时,会通过该方法将ApplicationContext对象注入。 以下是实现ApplicationContextAware接口方式的代码,前面两种方法类似: 虽然,spring提供的后三种方法可以实现在普通的类中继承或实现相应的类或接口来获取spring 的ApplicationContext对象,但是在使用是一定要注意实现了这些类或接口的普通java类一定要在Spring 的配置文件applicationContext.xml文件中进行配置。否则获取的ApplicationContext对象将为null。 方法六:通过Spring提供的ContextLoader(有使用条件) 最后提供一种不依赖于servlet,不需要注入的方式。但是需要注意一点,在服务器启动时,Spring容器初始化时,不能通过以下方法获取Spring 容器,细节可以查看spring源码org.springframework.web.context.ContextLoader。 方法七:实现接口BeanFactoryAware(与ApplicationContextAware类似) 自定义一个工具类,实现自BeanFactoryAware接口,接口的方法是setBeanFactory,我们实现它,并让其为我们服务,因为Spring在load自己的时候会将上下文环境填充进来。 题外:

yml 文件简解

转: 什么是YAML YAML是”YAML Ain’t a Markup Language”(YAML不是一种标记语言)的递归缩写。YAML的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)。主要强度这种语音是以数据为中心,而不是以标记语音为重心,例如像xml语言就会使用大量的标记。 YAML是一个可读性高,易于理解,用来表达数据序列化的格式。它的语法和其他高级语言类似,并且可以简单表达清单(数组)、散列表,标量等数据形态。它使用空白符号缩进和大量依赖外观的特色,特别适合用来表达或编辑数据结构、各种配置文件等。 YAML的配置文件后缀为 .yml,例如Springboot项目中使用到的配置文件 application.yml 。 基本语法 YAML使用可打印的Unicode字符,可使用UTF-8或UTF-16。 数据结构采用键值对的形式,即 键名称: 值,注意冒号后面要有空格。 每个清单(数组)成员以单行表示,并用短杠+空白(- )起始。或使用方括号([]),并用逗号+空白(, )分开成员。 每个散列表的成员用冒号+空白(: )分开键值和内容。或使用大括号({ }),并用逗号+空白(, )分开。 字符串值一般不使用引号,必要时可使用,使用双引号表示字符串时,会转义字符串中的特殊字符(例如\n)。使用单引号时不会转义字符串中的特殊字符。 大小写敏感 使用缩进表示层级关系,缩进不允许使用tab,只允许空格,因为有可能在不同系统下tab长度不一样 缩进的空格数可以任意,只要相同层级的元素左对齐即可 在单一文件中,可用连续三个连字号(—)区分多个文件。还有选择性的连续三个点号(…)用来表示文件结尾。 ‘#’表示注释,可以出现在一行中的任何位置,单行注释 在使用逗号及冒号时,后面都必须接一个空白字符,所以可以在字符串或数值中自由加入分隔符号(例如:5,280或http://www.wikipedia.org)而不需要使用引号。 数据类型 纯量(scalars):单个的、不可再分的值 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary) 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list) 标量 标量是最基础的数据类型,不可再分的值,他们一般用于表示单个的变量,有以下七种: 字符串 布尔值 整数 浮点数 Null 时间 日期 # 字符串string.value: Hello!我是陈皮!# […]

Spring-Retry重试机制

转:https://mp.weixin.qq.com/s/n4BKECgc5lFPM8LX6OTOqQ # 概要 **** Spring实现了一套重试机制,功能简单实用。Spring Retry是从Spring Batch独立出来的一个功能,已经广泛应用于Spring Batch,Spring Integration, Spring for Apache Hadoop等Spring项目。本文将讲述如何使用Spring Retry及其实现原理。 # 背景 **** 重试,其实我们其实很多时候都需要的,为了保证容错性,可用性,一致性等。一般用来应对外部系统的一些不可预料的返回、异常等,特别是网络延迟,中断等情况。还有在现在流行的微服务治理框架中,通常都有自己的重试与超时配置,比如dubbo可以设置retries=1,timeout=500调用失败只重试1次,超过500ms调用仍未返回则调用失败。 如果我们要做重试,要为特定的某个操作做重试功能,则要硬编码,大概逻辑基本都是写个循环,根据返回或异常,计数失败次数,然后设定退出条件。这样做,且不说每个操作都要写这种类似的代码,而且重试逻辑和业务逻辑混在一起,给维护和扩展带来了麻烦。从面向对象的角度来看,我们应该把重试的代码独立出来。 # 使用介绍 **** 基本使用 先举个例子: @EnableRetry – 表示开启重试机制 @Retryable – 表示这个方法需要重试,它有很丰富的参数,可以满足你对重试的需求 @Backoff – 表示重试中的退避策略 @Recover – 兜底方法,即多次重试后还是失败就会执行这个方法 Spring-Retry 的功能丰富在于其重试策略和退避策略,还有兜底,监听器等操作。 然后每个注解里面的参数,都是很简单的,大家看一下就知道是什么意思,怎么用了,我就不多讲了。 重试策略 看一下Spring Retry自带的一些重试策略,主要是用来判断当方法调用异常时是否需要重试。(下文原理部分会深入分析实现) SimpleRetryPolicy 默认最多重试3次 TimeoutRetryPolicy 默认在1秒内失败都会重试 ExpressionRetryPolicy 符合表达式就会重试 CircuitBreakerRetryPolicy 增加了熔断的机制,如果不在熔断状态,则允许重试 CompositeRetryPolicy 可以组合多个重试策略 NeverRetryPolicy 从不重试(也是一种重试策略哈) AlwaysRetryPolicy […]

VPN过滤规则

大致上说明下 DOMAIN-SUFFIX 基于域名后缀判断。输入 baidu.com 就可以过滤zhidao.baidu.com,pan.baidu.comd等 baidu.com 后缀的网站。 DOMAIN-KEYWORD 基于关键词的判断。输入baidu,就可以过滤 baidu.com,baidu.jp等含有 baidu 字眼的网站。 DOMAIN 基于域名的判断。输入 www.baidu.com 就可以过滤 www.baidu.com/*的网站。 IP-CIDR 判断是否为局域网。 GEOIP 判断服务器地址。Surge 是可以选择的,但是之类好像只能自己填写,比如 JP,CN 之类的。 FINAL 剩余的网站。 过滤网址之后 过滤网址之后,对其进行操作,你可以选择走代理 PROXY,或者直连 DIRECT,或者拒绝访问 REJECT。

SpringBoot常用注解

# 注解(annotations)列表 **** @SpringBootApplication: 包含了@ComponentScan、@Configuration和@EnableAutoConfiguration注解。其中@ComponentScan让spring Boot扫描到Configuration类并把它加入到程序上下文。 @Configuration 等同于spring的XML配置文件;使用Java代码可以检查类型安全。 @EnableAutoConfiguration 自动配置。 @ComponentScan 组件扫描,可自动发现和装配一些Bean。 @Component 可配合CommandLineRunner使用,在程序启动后执行一些基础任务。 @RestController 注解是@Controller和@ResponseBody的合集,表示这是个控制器bean,并且是将函数的返回值直 接填入HTTP响应体中,是REST风格的控制器。 @Autowired 自动导入。 @PathVariable 获取参数。 @JsonBackReference 解决嵌套外链问题。 @RepositoryRestResourcepublic 配合spring-boot-starter-data-rest使用。 # 注解(annotations)详解 **** @SpringBootApplication: 申明让spring boot自动给程序进行必要的配置,这个配置等同于:@Configuration ,@EnableAutoConfiguration 和 @ComponentScan 三个配置。 @ResponseBody: 表示该方法的返回结果直接写入HTTP response body中,一般在异步获取数据时使用,用于构建RESTful的api。在使用@RequestMapping后,返回值通常解析为跳转路径,加上@responsebody后返回结果不会被解析为跳转路径,而是直接写入HTTP response body中。 比如异步获取json数据,加上@responsebody后,会直接返回json数据。该注解一般会配合@RequestMapping一起使用。 示例代码: @Controller: 用于定义控制器类,在spring 项目中由控制器负责将用户发来的URL请求转发到对应的服务接口(service层),一般这个注解在类中,通常方法需要配合注解@RequestMapping。 示例代码: @RestController: 用于标注控制层组件(如struts中的action),@ResponseBody和@Controller的合集。 示例代码: @RequestMapping: 提供路由信息,负责URL到Controller中的具体函数的映射。 @EnableAutoConfiguration:Spring Boot自动配置(auto-configuration):尝试根据你添加的jar依赖自动配置你的Spring应用。例如,如果你的classpath下存在HSQLDB,并且你没有手动配置任何数据库连接beans,那么我们将自动配置一个内存型(in-memory)数据库”。 你可以将@EnableAutoConfiguration或者@SpringBootApplication注解添加到一个@Configuration类上来选择自动配置。如果发现应用了你不想要的特定自动配置类,你可以使用@EnableAutoConfiguration注解的排除属性来禁用它们。 […]

10种编程语言实现Y组合子

转自:阿里技术 一 Y-Combinator Y组合子是Lambda演算的一部分,也是函数式编程的理论基础。它是一种方法/技巧,在没有赋值语句的前提下定义递归的匿名函数。即仅仅通过Lambda表达式这个最基本的“原子”实现循环/迭代,颇有道生一、一生二、二生三、三生万物的感觉。 1 从递归的阶乘函数开始 先不考虑效率等其他因素,写一个最简单的递归阶乘函数。此处采用Scheme,你可以选择自己熟悉的编程语言跟着我一步一步实现Y-Combinator版的阶乘函数。 Scheme中 (define (fn-name)) 是 (define fn-name (lambda)) 的简写,就像JS中,function foo() {} 等价于 var foo = function() {}。把上面的定义展开成Lambda的定义: 2 绑定函数名 想要递归地调用一个函数,就必须给这个函数取一个名字。匿名函数想要实现递归,就得取一个临时的名字。所谓临时,指这个名字只在此函数体内有效,函数执行完成后,这个名字就伴随函数一起消失。为解决这个问题,第一篇文章中[1]强制规定匿名函数有一个隐藏的名字this指向自己,这导致this这个变量名被强行占用,并不优雅,因此第二篇文章[2]借鉴Clojure的方法,允许自定义一个名字。 但在Lambda演算中,只有最普通的Lambda,没有赋值语句,如何绑定一个名字呢?答案是使用Lambda的参数列表! 3 生成阶乘函数的函数 虽然通过参数列表,即使用闭包技术给匿名函数取了一个名字,但此函数并不是我们想要的阶乘函数,而是阶乘函数的元函数(meta-factorial),即生成阶乘函数的函数。因此需要执行这个元函数,获得想要的阶乘函数: 此时又出现另一个问题:实参xxx,即形参factorial该取什么值?从定义来看,factorial就是函数自身,既然是“自身”,首先想到的就是复制一份一模一样的代码: 看起来已经把自己传递给了自己,但马上发现 (factorial (- n 1)) 会失败,因为此时的 factorial 不是一个阶乘函数,而是一个包含阶乘函数的函数,即要获取包含在内部的函数,因此调用方式要改成 ((meta-factorial meta-factorial) (- n 1)) : 把名字改成meta-factorial就能清晰地看出它是阶乘的元函数,而不是阶乘函数本身。 4 去除重复 以上代码已经实现了lambda的自我调用,但其中包含重复的代码,meta-factorial即做函数又做参数,即 (meta meta) : 5 提取阶乘函数 因为我们想要的是阶乘函数,所以用factorial取代 […]

Java 16 …

JEP 396: Strongly Encapsulate JDK Internals by Default 主要影响是部分基于反射的功能。比如lombok, 解决方法是升级lombok版本到 1.18.20 相关: https://projectlombok.org/changelog https://github.com/rzwitserloot/lombok/issues/2681 针对: java.lang.reflect.InaccessibleObjectException: Unable to make {member} accessible: module {A} does not “opens {package} ” to {B} 解决方法是在Java的VM参数中添加 –add-opens java.base/java.lang=ALL-UNNAMED 参考:https://www.lwohvye.com/2021/04/09/java-lang-reflect-inaccessibleobjectexception-unable-to-make-member-accessible-module-a-does-not-opens-package-to-b/ JEP 395: Records 关于Records 和 lombok,参考:https://stackoverflow.com/questions/61306802/lombok-getter-setter-vs-java-14-record/61325018#61325018

java.lang.reflect.InaccessibleObjectException: Unable to make {member} accessible: module {A} does not “opens {package} ” to {B}

How to solve InaccessibleObjectException (“Unable to make {member} accessible: module {A} does not ‘opens {package}’ to {B}”) on Java 9 or later? 在Java 9上运行应用程序时,在许多情况下都会发生此异常。 某些库和框架(Spring,Hibernate,JAXB)特别容易使用。 这是来自Javassist的示例: 该消息显示: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not”opens java.lang” to unnamed module @1941a8ff 如何避免发生异常并使程序成功运行? 该异常是由Java 9中引入的Java平台模块系统引起的,特别是其强封装的实现。 它仅允许在特定条件下访问,最突出的条件是: 类型必须是公开的 拥有包必须导出 对于反射,导致异常的代码尝试使用相同的限制。 更确切地说,该异常是由对setAccessible的调用引起的。 这可以在上面的堆栈跟踪中看到,其中javassist.util.proxy.SecurityActions中的相应行如下所示: […]

七种方式教你在 SpringBoot 初始化时搞点事情

我们经常需要在容器启动的时候做一些钩子动作,比如注册消息消费者,监听配置等,今天就总结下 SpringBoot 留给开发者的 7 个启动扩展点。 容器刷新完成扩展点 **** 1.1 监听容器刷新完成扩展点 ApplicationListener 基本用法 熟悉 Spring 的同学一定知道,容器刷新成功意味着所有的 Bean 初始化已经完成,当容器刷新之后Spring将会调用容器内所有实现了ApplicationListener的Bean的 onApplicationEvent 方法,应用程序可以以此达到监听容器初始化完成事件的目的。 易错的点 这个扩展点用在 web 容器中的时候需要额外注意,在 web 项目中(例如 spring mvc),系统会存在两个容器,一个是 root application context,另一个就是我们自己的 context(作为 root application context 的子容器)。如果按照上面这种写法,就会造成 onApplicationEvent 方法被执行两次。解决此问题的方法如下: 高阶玩法 当然这个扩展还可以有更高阶的玩法:自定义事件,可以借助 Spring 以最小成本实现一个观察者模式: 先自定义一个事件: 注册一个事件监听器 发布事件 执行单元测试可以看到邮件的地址和内容都被打印出来了 1.2 SpringBoot 的 CommandLineRunner 接口 当容器上下文初始化完成之后,SpringBoot 也会调用所有实现了 CommandLineRunner 接口的 run 方法,下面这段代码可起到和上文同样的作用: […]

lWoHvYe 无悔,专一