Bean初始化
Bean初始化过程如果说配置文件好比菜谱,解析配置文件好比洗菜、切菜,那么Bean初始化过程就好比炒菜的过程。Spring的核心基础就建立在对Bean的管理功能上。如何定义一个Bean,如何获取一个Bean,如何初始化一个Bean,如何销毁一个Bean。
getBean方法 – 炒菜开始的信号想象一下getBean的场景,好比是食客点了一道菜(或者说菜单是由食客提供的,厨房代加工),厨房根据菜单做菜。想象一下在这个过程中需要做哪些工作?
按照菜谱准备菜 – 解析配置文件
洗菜,切菜 - - 注册Bean定义
炒菜 – Bean 初始化
添加额外的佐料 – 动态注册Bean定义
第1,2步可以看成是同时进行的,边准备菜,边洗菜切菜也就是边解析边注册。getBean 方法由BeanFactory接口提供。
BeanFactoryBeanFactory接口是整个Spring容器的核心接口。提供了多个获取 Bean 的方法。
Object getBean(String name) throws BeansException;
T getBean(String name, Class r ...
错误: 未报告的异常错误X; 必须对其进行捕获或声明以便抛出
今天在jdk8环境中碰到一个诡异的异常:
错误: 未报告的异常错误X; 必须对其进行捕获或声明以便抛出
jdk8方便是方便,但是有点儿不好排查问题。看提示应该是有个方法抛出了异常,只能按方法去排查了。最后在java.util.Optional#orElseThrow方法中找到了疑似代码。java.util.Optional#orElseThrow:
12345678 public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { if (value != null) { return value; } else { throw exceptionSupplier.get(); }}
方法参数为异常产生器,X是Throwable的子类。
我的原始写法是:
1.orElseThrow(() -> {throw new ...
Spring bean定义文件解析
Bean 定义文件的解析初始化工厂123456// 1. 初始化一个bean 工厂DefaultListableBeanFactory factory = new DefaultListableBeanFactory();// 2. 初始化XmlBeanDefinitionReader,负责从xml文件中读取bean定义XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);// 3. 加载bean 定义的入口方法reader.loadBeanDefinitions("classpath:app.xml");
上述代码使用起来很简单,创建一个工厂和阅读器,传入配置文件的位置。
我们可以考虑一下,这些代码做了什么。
XmlBeanDefinitionReader 是如何定位配置文件的?
如何解析配置文件的?
XmlBeanDefinitionReader的构造函数传入了一个BeanDefinitionRegistry对象,这个对象是用来注册bean定义的,那么是如何注册的呢?
R ...
Spring自定义命名空间解析
自定义命名空间解析当我们想要扩展Spring 的配置时,可以定义我们自己的标签,然后解析成 bean定义,注册到Spring 容器中。这时需要用到 NamespaceHandler。Spring 框架中除了beans顶级标签外,其他的顶级标签都是自定义命名空间中的标签。如,p、 c、util命名空间。
NamespaceHandler 命名空间解析器Spring 框架中mvc、context、tx 等功能都是通过扩展这个接口来实现的。这个接口负责将标签解析成bean 定义对象。该接口提供了parse 和decorate 方法。parse方法用来将顶级标签解析成BeanDefinition对象。decorate 方法负责对parse出来的BeanDefinition进行进一步处理,需要解析的可以是元素属性和标签。 可以返回原来的BeanDefinition,或者返回一个新的BeanDefinition。
为了解析的方便,Spring 提供了一个抽象类NamespaceHandlerSupport,封装了一些基础功能,并提供了两个新的接口(BeanDefinitionParser和Bean ...
Spring ApplicationContext初始化过程
在ApplicationContext初始化过程中各组件所处的位置。
Spring 常用接口
Spring 常用接口Bean 工厂相关BeanFactory
这个接口是访问Spring bean 容器的顶层接口。实现类会持有一些bean定义,每一个都有唯一的名称。根据bean定义,这个工厂将返回一个独立的(原型设计模式),或者是一个共享的实例(单例模式的强力替代品,实例在工厂的生存周期内是一个单例),返回的实例类型取决于工厂配置。
这种方式的要点是BeanFactory是应用程序组件的注册中心,并集中配置应用的组件(例如,单个对象不再需要读取配置文件)。
ListableBeanFactory继承自BeanFactory, 这个接口的用途是枚举所有bean 实例,而不是客户端通过名称一个个查找。
HierarchicalBeanFactory这个接口用来实现工厂的继承关系,
AutowireCapableBeanFactory此工厂提供bean自动注入功能。
ConfigurableBeanFactory提供配置bean工厂的功能,但是此工厂一般是框架内部使用。
ConfigurableListableBeanFactory提供分析和修改bean定义和预初始化单例bean的功能 ...
年会
果然不出意外,今年年会又没中奖。号码为96, 这么顺的号码,依然没中。果然是没有中奖的运气,长这么大好像没中过。总共160人左右,56个奖品,中奖率35%左右。我坐的是11号桌,10个人有7个中奖了,跟我邻座的同事没中。感觉有点儿被愚弄了啊。
创建my-jpa初衷
现在项目中大多数都用Mybatis来做持久化框架,虽然mybatis很灵活,能够定制sql,但是在基础的curd功能上,还是很繁琐,每次都需要创建xml文件,添加相应的sql。也有一些第三方框架如mybatis-plus等,对mybatis做了增强,提供了基础的curd,以及其他的高级功能。但是需要在我们的源代码上加入一些框架里的注解,侵入性大。如果需要更换为hibernate,则代码更改起来非常麻烦,而且这些注解在jpa中都已经定义好了。因此在想如果让mybatis-plus支持jpa的注解就可以了,最开始也只打算做到这一步。但是无意中看到了spring-data-jpa,发现spring对jpa提供了更好的支持,比如通过方法名来转换成查询条件。因此在想干脆用mybatis来实现一个jpa,一来是使用标准的注解,二来是保持mybatis的灵活性。由此便有了my-jpa项目。
my-jpa项目需要达到的目标:
支持jpa的大部分注解。
支持mybatis的sql定制。
集成spring-data-jpa。
org.springframework.boot.actuate.endpoint.EndpointId cannot be cast to java.lang.String 异常处理
用了spring-boot-starter-actuator 之后出现异常: java.lang.ClassCastException: org.springframework.boot.actuate.endpoint.EndpointId cannot be cast to java.lang.String.详细的异常如下:
123456789101112131415161718192021222324Failed to instantiate [org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar]: Factory method 'servletEndpointRegistrar' threw exception; nested exception is java.lang.ClassCastException: org.springframework.boot.actuate.endpoint.EndpointId cannot be cast to java.l ...
在controller 参数中使用枚举
我们通常将一些固定的值定义为枚举类型, 这样就可以限制别人在接口中不能随便传参数,只能是其中的几个.
但是作为框架的设计者, 这样定义之后,框架的使用者想要扩展的话非学不方便, 因为枚举类型默认就继承Enum 类型,无法再继承其他的类. 因此我们考虑将枚举类实现一个接口,同时,使用时也是用这个接口来定义变量类型.
定义枚举接口:
1234567891011121314public interface IEnum<T> extends Serializable { /** * @return */ default Object getValue() { return name(); } /** * @return 默认就是枚举值的name */ String name();}
再定义一个子接口来表示某一类枚举值:
123456789101112public interface FormFiledType extends IEnum { ...