Spring实战系列(三)-BeanPostProcessor的妙用
04-09 阅读数 6683
"对于Spring框架,现实公司使用的非常广泛,但是由于业务的复杂程度不同,了解到很多小伙伴们利用Spring开发仅仅是利用了Spring的IOC,即使是AOP也很少用,但是目前的Sprin... 博文 来自: jokeHello的专栏
赞
踩
BeanPostProcessor是Spring IOC容器给我们提供的一个扩展接口。接口声明如下:
-
public
interface BeanPostProcessor {
-
//bean初始化方法调用前被调用
-
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
-
//bean初始化方法调用后被调用
-
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
-
-
}
如上接口声明所示,BeanPostProcessor接口有两个回调方法。当一个BeanPostProcessor的实现类注册到Spring IOC容器后,对于该Spring IOC容器所创建的每个bean实例在初始化方法(如afterPropertiesSet和任意已声明的init方法)调用前,将会调用BeanPostProcessor中的postProcessBeforeInitialization方法,而在bean实例初始化方法调用完成后,则会调用BeanPostProcessor中的postProcessAfterInitialization方法,整个调用顺序可以简单示意如下:
--> Spring IOC容器实例化Bean
--> 调用BeanPostProcessor的postProcessBeforeInitialization方法
--> 调用bean实例的初始化方法
--> 调用BeanPostProcessor的postProcessAfterInitialization方法
可以看到,Spring容器通过BeanPostProcessor给了我们一个机会对Spring管理的bean进行再加工。比如:我们可以修改bean的属性,可以给bean生成一个动态代理实例等等。一些Spring AOP的底层处理也是通过实现BeanPostProcessor来执行代理包装逻辑的。
了解了BeanPostProcessor的相关知识后,下面我们来通过项目中的一个具体例子来体验一下它的神奇功效吧。
先介绍一下我们的项目背景吧:我们项目中经常会涉及AB 测试,这就会遇到同一套接口会存在两种不同实现。实验版本与对照版本需要在运行时同时存在。下面用一些简单的类来做一个示意:
-
public
class HelloService{
-
void sayHello();
-
void sayHi();
-
}
HelloService有以下两个版本的实现:
-
@Service
-
public
class HelloServiceImplV1 implements HelloService{
-
public void sayHello(){
-
System.out.println(
"Hello from V1");
-
}
-
public void sayHi(){
-
System.out.println(
"Hi from V1");
-
}
-
}
-
@Service
-
public
class HelloServiceImplV2 implements HelloService{
-
public void sayHello(){
-
System.out.println(
"Hello from V2");
-
}
-
public void sayHi(){
-
System.out.println(
"Hi from V2");
-
}
-
}
做AB测试的话,在使用BeanPostProcessor封装前,我们的调用代码大概是像下面这样子的:
-
@Controller
-
public
class HelloController{
-
@Autowird
-
private HelloServiceImplV1 helloServiceImplV1;
-
@Autowird
-
private HelloServiceImplV2 helloServiceImplV2;
-
-
public void sayHello(){
-
if(getHelloVersion()==
"A"){
-
helloServiceImplV1.sayHello();
-
}
else{
-
helloServiceImplV2.sayHello();
-
}
-
}
-
public void sayHi(){
-
if(getHiVersion()==
"A"){
-
helloServiceImplV1.sayHi();
-
}
else{
-
helloServiceImplV2.sayHi();
-
}
-
}
-
}
可以看到,这样的代码看起来十分不优雅,并且如果AB测试的功能点很多的话,那项目中就会充斥着大量的这种重复性分支判断,看到代码就想死有木有!!!维护代码也将会是个噩梦。比如某个功能点AB测试完毕,需要把全部功能切换到V2版本,V1版本不再需要维护,那么处理方式有两种:
怎么解决这个问题呢,我们先看代码,后文再给出解释:
-
@Target({ElementType.FIELD})
-
@Retention(RetentionPolicy.RUNTIME)
-
@Documented
-
@Component
-
public
@interface RoutingInjected{
-
}
-
@Target({ElementType.FIELD,ElementType.METHOD})
-
@Retention(RetentionPolicy.RUNTIME)
-
@Documented
-
@Component
-
public
@interface RoutingSwitch{
-
/**
-
* 在配置系统中开关的属性名称,应用系统将会实时读取配置系统中对应开关的值来决定是调用哪个版本
-
* @return
-
*/
-
String value()
default
"";
-
}
-
-
@RoutingSwitch(
"hello.switch")
-
public
class HelloService{
-
-
@RoutingSwitch(
"A")
-
void sayHello();
-
-
void sayHi();
-
}
-
@Controller
-
public
class HelloController{
-
-
@RoutingInjected
-
private HelloService helloService;
-
-
public void sayHello(){
-
this.helloService.sayHello();
-
}
-
-
public void sayHi(){
-
this.helloService.sayHi();
-
}
-
}
现在我们可以停下来对比一下封装前后调用代码了,是不是感觉改造后的代码优雅很多呢?那么这是怎么实现的呢,我们一起来揭开它的神秘面纱吧,请看代码:
-
@Component
-
public
class RoutingBeanPostProcessor implements BeanPostProcessor {
-
-
@Autowired
-
private ApplicationContext applicationContext;
-
-
@Override
-
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
-
return bean;
-
}
-
-
@Override
-
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
-
Class clazz = bean.getClass();
-
Field[] fields = clazz.getDeclaredFields();
-
for (Field f : fields) {
-
if (f.isAnnotationPresent(RoutingInjected.class)) {
-
if (!f.getType().isInterface()) {
-
throw
new BeanCreationException(
"RoutingInjected field must be declared as an interface:" + f.getName()
-
+
" @Class " + clazz.getName());
-
}
-
try {
-
this.handleRoutingInjected(f, bean, f.getType());
-
}
catch (IllegalAccessException e) {
-
throw
new BeanCreationException(
"Exception thrown when handleAutowiredRouting", e);
-
}
-
}
-
}
-
return bean;
-
}
-
-
private void handleRoutingInjected(Field field, Object bean, Class type) throws IllegalAccessException {
-
Map<String, Object> candidates =
this.applicationContext.getBeansOfType(type);
-
field.setAccessible(
true);
-
if (candidates.size() ==
1) {
-
field.set(bean, candidates.values().iterator().next());
-
}
else
if (candidates.size() ==
2) {
-
Object proxy = RoutingBeanProxyFactory.createProxy(type, candidates);
-
field.set(bean, proxy);
-
}
else {
-
throw
new IllegalArgumentException(
"Find more than 2 beans for type: " + type);
-
}
-
}
-
}
-
-
public
class RoutingBeanProxyFactory {
-
-
public static Object createProxy(Class targetClass, Map<String, Object> beans) {
-
ProxyFactory proxyFactory = new ProxyFactory();
-
proxyFactory.setInterfaces(targetClass);
-
proxyFactory.addAdvice(new VersionRoutingMethodInterceptor(targetClass, beans));
-
return proxyFactory.getProxy();
-
}
-
static
class VersionRoutingMethodInterceptor implements MethodInterceptor {
-
private String classSwitch;
-
private Object beanOfSwitchOn;
-
private Object beanOfSwitchOff;
-
-
public VersionRoutingMethodInterceptor(Class targetClass, Map<String, Object> beans) {
-
String interfaceName = StringUtils.uncapitalize(targetClass.getSimpleName());
-
if(targetClass.isAnnotationPresent(RoutingSwitch.
class)){
-
this.classSwitch =((RoutingSwitch)targetClass.getAnnotation(RoutingSwitch.
class)).value();
-
}
-
this.beanOfSwitchOn = beans.
get(
this.buildBeanName(interfaceName,
true));
-
this.beanOfSwitchOff = beans.
get(
this.buildBeanName(interfaceName,
false));
-
}
-
-
private String buildBeanName(String interfaceName, boolean isSwitchOn) {
-
return interfaceName +
"Impl" + (isSwitchOn ?
"V2" :
"V1");
-
}
-
-
@Override
-
public Object invoke(MethodInvocation invocation) throws Throwable {
-
Method method = invocation.getMethod();
-
String switchName =
this.classSwitch;
-
if (method.isAnnotationPresent(RoutingSwitch.
class)) {
-
switchName = method.getAnnotation(RoutingSwitch.
class).value();
-
}
-
if (StringUtils.isBlank(switchName)) {
-
throw new IllegalStateException(
"RoutingSwitch's value is blank, method:" + method.getName());
-
}
-
return invocation.getMethod().invoke(getTargetBean(switchName), invocation.getArguments());
-
}
-
-
public Object getTargetBean(String switchName) {
-
boolean switchOn;
-
if (RoutingVersion.A.equals(switchName)) {
-
switchOn =
false;
-
}
else
if (RoutingVersion.B.equals(switchName)) {
-
switchOn =
true;
-
}
else {
-
switchOn = FunctionSwitch.isSwitchOpened(switchName);
-
}
-
return switchOn ? beanOfSwitchOn : beanOfSwitchOff;
-
}
-
}
-
}
-
我简要解释一下思路:
好了,BeanPostProcessor的介绍就到这里了。不知道看过后大家有没有得到一些启发呢?欢迎大家留言交流反馈。今天就到这里,我们下期再见吧 哈哈哈
<li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true"> <use xlink:href="#csdnc-thumbsup"></use> </svg><span class="name">点赞</span> <span class="count">2</span> </a></li> <li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{"mod":"popu_824"}"><svg class="icon" aria-hidden="true"> <use xlink:href="#icon-csdnc-Collection-G"></use> </svg><span class="name">收藏</span></a></li> <li class="tool-item tool-active is-share"><a href="javascript:;"><svg class="icon" aria-hidden="true"> <use xlink:href="#icon-csdnc-fenxiang"></use> </svg>分享</a></li> <!--打赏开始--> <!--打赏结束--> <li class="tool-item tool-more"> <a> <svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg> </a> <ul class="more-box"> <li class="item"><a class="article-report">文章举报</a></li> </ul> </li> </ul> </div> </div> <div class="person-messagebox"> <div class="left-message"><a href="https://blog.csdn.net/u011121287"> <img src="https://profile.csdnimg.cn/4/5/D/3_u011121287" class="avatar_pic" username="u011121287"> <img src="https://g.csdnimg.cn/static/user-reg-year/2x/7.png" class="user-years"> </a></div> <div class="middle-message"> <div class="title"><span class="tit"><a href="https://blog.csdn.net/u011121287" data-report-click="{"mod":"popu_379"}" target="_blank">gold_zwj</a></span> </div> <div class="text"><span>发布了82 篇原创文章</span> · <span>获赞 14</span> · <span>访问量 7万+</span></div> </div> <div class="right-message"> <a href="https://im.csdn.net/im/main.html?userName=u011121287" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-letter">私信 </a> <a class="btn btn-sm bt-button personal-watch" data-report-click="{"mod":"popu_379"}">关注</a> </div> </div> </div> </article>
<script>
$("#blog_detail_zk_collection").click(function(){
window.csdn.articleCollection()
})
<div class="recommend-box"><div class="recommend-item-box type_blog clearfix" data-report-click="{"mod":"popu_387","dest":"https://blog.csdn.net/qq_18297675/article/details/87957540","strategy":"BlogCommendFromMachineLearnPai2","index":"0"}"> <div class="content" style="width: 712px;"> <a href="https://blog.csdn.net/qq_18297675/article/details/87957540" target="_blank" rel="noopener" title="springboot之BeanPostProcessor功能及例子(一)"> <h4 class="text-truncate oneline" style="width: 552px;"> springboot之<em>BeanPostProcessor</em>功能及例子(一) </h4> <div class="info-box d-flex align-content-center"> <p class="date-and-readNum oneline"> <span class="date hover-show">02-26</span> <span class="read-num hover-hide"> 阅读数 2831</span> </p> </div> </a> <p class="content" style="width: 712px;"> <a href="https://blog.csdn.net/qq_18297675/article/details/87957540" target="_blank" rel="noopener" title="springboot之BeanPostProcessor功能及例子(一)"> <span class="desc oneline">一、BeanPostProcessor字面上的意思是bean的后置处理器,什么意思呢?其实就是说,在bean的生命周期中,可以对它干什么。再简单点就是,bean初始化之前干点什么,之后又干点什么。pu...</span> </a> <span class="blog_title_box oneline "> <span class="type-show type-show-blog type-show-after">博文</span> <a target="_blank" rel="noopener" href="https://blog.csdn.net/qq_18297675">来自: <span class="blog_title"> _ACME_的博客</span></a> </span> </p> </div> </div>
04-09 阅读数 6683
"对于Spring框架,现实公司使用的非常广泛,但是由于业务的复杂程度不同,了解到很多小伙伴们利用Spring开发仅仅是利用了Spring的IOC,即使是AOP也很少用,但是目前的Sprin... 博文 来自: jokeHello的专栏
07-28 阅读数 2088
在合理的范围内,经常给自己加戏,才能得到锻炼和被指导的机会。前段时间,看到公司的大牛用到了注解,来将从配置中心获取配置文件中的属性在bean加载后注入到bean的属性中去,于是自己尝试了一下,代码如下... 博文 来自: fzghjx的博客
11-22 阅读数 2万+
前言BeanPostProcessor是一个工厂钩子,允许在新创建Bean实例时对其进行定制化修改。例如:检查其标注的接口或者使用代理对其进行包裹。应用上下文会从Bean定义中自动检测出BeanPos... 博文 来自: 不动明王1984的博客
<div class="recommend-item-box recommend-recommend-box"><div id="kp_box_59" data-pid="59"><script type="text/javascript">
(function() {
var s = "_" + Math.random().toString(36).slice(2);
document.write('<div style="" id="' + s + '"></div>');
(window.slotbydup = window.slotbydup || []).push({
id: "u3491668",
container: s
});
})();
09-06 阅读数 3307
各位同学们,好久没写原创技术文章了,最近有些忙,所以进度很慢,给大家道个歉。> 警告:本教程仅用作学习交流,请勿用作商业盈利,违者后果自负!如本文有侵犯任何组织集团公司的隐私或利益,请告知联系猪... 博文
07-21 阅读数 102
Spring提供了很多扩展接口,BeanPostProcessor接口和InstantiationAwareBeanPostProcessor接口就是其中两个。 BeanPostProcessorBe... 博文 来自: 每天进步一点点
09-16 阅读数 8万+
引言最近也有很多人来向我"请教",他们大都是一些刚入门的新手,还不了解这个行业,也不知道从何学起,开始的时候非常迷茫,实在是每天回复很多人也很麻烦,所以在这里统一作个回复吧。Java学习路线当然,这里... 博文 来自: java_sha的博客
05-20 阅读数 61
上面两篇文章分别介绍了spring生命周期中初始化和销毁的几种方式以及统一后置BeanPostProcessor接口的使用,可以点击以下链接查看:三分钟了解spring-bean生命周期之初始化和销毁... 博文 来自: weixin_33748818的博客
<div class="recommend-item-box recommend-recommend-box"><div id="kp_box_60" data-pid="60"><script type="text/javascript">
(function() {
var s = "_" + Math.random().toString(36).slice(2);
document.write('<div style="" id="' + s + '"></div>');
(window.slotbydup = window.slotbydup || []).push({
id: "u3502456",
container: s
});
})();
06-24 阅读数 8
BeanPostProcessor简介BeanPostProcessor是Spring IOC容器给我们提供的一个扩展接口。接口声明如下:public interface BeanPostProces... 博文 来自: dimei8552的博客
<div class="recommend-item-box blog-expert-recommend-box" style="display: block;">
<div class="d-flex">
<div class="blog-expert-recommend">
<div class="blog-expert">
<div class="blog-expert-flexbox"><div class="blog-expert-item"><div class="blog-expert-info-box"><div class="blog-expert-img-box" data-report-click="{"mod":"popu_709","dest":"https://blog.csdn.net/zwjyyy1203/article/details/89576084"}"><a href="https://blog.csdn.net/qq_18297675" target="_blank"><img src="https://profile.csdnimg.cn/2/5/1/3_qq_18297675" username="qq_18297675" alt="_acme_" title="_acme_"><svg class="icon" aria-hidden="true"><use xlink:href="#csdnc-blogexpert"></use></svg></a><span data-report-click="{"mod":"popu_710","dest":"https://blog.csdn.net/zwjyyy1203/article/details/89576084"}"><span class="blog-expert-button-follow btn-red-follow" data-name="qq_18297675" data-nick="_acme_">关注</span></span></div><div class="info"><span data-report-click="{"mod":"popu_709","dest":"https://blog.csdn.net/zwjyyy1203/article/details/89576084"}"><a href="https://blog.csdn.net/qq_18297675" target="_blank"><h5 class="oneline" title="_acme_">_acme_</h5></a></span> <p></p><p class="article-num" title="258篇文章"> 258篇文章</p><p class="article-num" title="排名:4000+"> 排名:4000+</p><p></p></div></div></div><div class="blog-expert-item"><div class="blog-expert-info-box"><div class="blog-expert-img-box" data-report-click="{"mod":"popu_709","dest":"https://blog.csdn.net/zwjyyy1203/article/details/89576084"}"><a href="https://blog.csdn.net/jokeHello" target="_blank"><img src="https://profile.csdnimg.cn/9/D/3/3_jokehello" username="jokeHello" alt="轻鸿飘羽" title="轻鸿飘羽"></a><span data-report-click="{"mod":"popu_710","dest":"https://blog.csdn.net/zwjyyy1203/article/details/89576084"}"><span class="blog-expert-button-follow btn-red-follow" data-name="jokeHello" data-nick="轻鸿飘羽">关注</span></span></div><div class="info"><span data-report-click="{"mod":"popu_709","dest":"https://blog.csdn.net/zwjyyy1203/article/details/89576084"}"><a href="https://blog.csdn.net/jokeHello" target="_blank"><h5 class="oneline" title="轻鸿飘羽">轻鸿飘羽</h5></a></span> <p></p><p class="article-num" title="314篇文章"> 314篇文章</p><p class="article-num" title="排名:千里之外"> 排名:千里之外</p><p></p></div></div></div><div class="blog-expert-item"><div class="blog-expert-info-box"><div class="blog-expert-img-box" data-report-click="{"mod":"popu_709","dest":"https://blog.csdn.net/zwjyyy1203/article/details/89576084"}"><a href="https://blog.csdn.net/fzghjx" target="_blank"><img src="https://profile.csdnimg.cn/A/2/5/3_fzghjx" username="fzghjx" alt="fzghjx" title="fzghjx"></a><span data-report-click="{"mod":"popu_710","dest":"https://blog.csdn.net/zwjyyy1203/article/details/89576084"}"><span class="blog-expert-button-follow btn-red-follow" data-name="fzghjx" data-nick="fzghjx">关注</span></span></div><div class="info"><span data-report-click="{"mod":"popu_709","dest":"https://blog.csdn.net/zwjyyy1203/article/details/89576084"}"><a href="https://blog.csdn.net/fzghjx" target="_blank"><h5 class="oneline" title="fzghjx">fzghjx</h5></a></span> <p></p><p class="article-num" title="19篇文章"> 19篇文章</p><p class="article-num" title="排名:千里之外"> 排名:千里之外</p><p></p></div></div></div><div class="blog-expert-item"><div class="blog-expert-info-box"><div class="blog-expert-img-box" data-report-click="{"mod":"popu_709","dest":"https://blog.csdn.net/zwjyyy1203/article/details/89576084"}"><a href="https://blog.csdn.net/m0_37962779" target="_blank"><img src="https://profile.csdnimg.cn/A/F/C/3_m0_37962779" username="m0_37962779" alt="不动明王1984" title="不动明王1984"></a><span data-report-click="{"mod":"popu_710","dest":"https://blog.csdn.net/zwjyyy1203/article/details/89576084"}"><span class="blog-expert-button-follow btn-red-follow" data-name="m0_37962779" data-nick="不动明王1984">关注</span></span></div><div class="info"><span data-report-click="{"mod":"popu_709","dest":"https://blog.csdn.net/zwjyyy1203/article/details/89576084"}"><a href="https://blog.csdn.net/m0_37962779" target="_blank"><h5 class="oneline" title="不动明王1984">不动明王1984</h5></a></span> <p></p><p class="article-num" title="30篇文章"> 30篇文章</p><p class="article-num" title="排名:千里之外"> 排名:千里之外</p><p></p></div></div></div></div>
</div>
</div>
</div>
</div><div class="recommend-item-box baiduSearch" data-report-click="{"mod":"popu_387","dest":"https://blog.csdn.net/omgkill/article/details/81666754","strategy":"searchFromBaidu1","index":"5"}" data-track-view="{"mod":"popu_387","dest":"https://blog.csdn.net/omgkill/article/details/81666754","strategy":"searchFromBaidu1","index":4,"extend1":"_"}" data-track-click="{"mod":"popu_387","dest":"https://blog.csdn.net/omgkill/article/details/81666754","strategy":"searchFromBaidu1","index":4,"extend1":"_"}" data-flg="true"> <a href="https://blog.csdn.net/omgkill/article/details/81666754" target="_blank"> <h4 class="text-truncate oneline" style="width: 626px;"><em>BeanPostProcessor</em>示例和理解 - 行简 - CSDN博客</h4> <div class="info-box d-flex align-content-center"> <p> <span class="date">11-22</span> </p> </div> </a> </div><div class="recommend-item-box baiduSearch" data-report-click="{"mod":"popu_387","dest":"https://blog.csdn.net/Qgwperfect/article/details/83508772","strategy":"searchFromBaidu1","index":"6"}" data-track-view="{"mod":"popu_387","dest":"https://blog.csdn.net/Qgwperfect/article/details/83508772","strategy":"searchFromBaidu1","index":5,"extend1":"_"}" data-track-click="{"mod":"popu_387","dest":"https://blog.csdn.net/Qgwperfect/article/details/83508772","strategy":"searchFromBaidu1","index":5,"extend1":"_"}" data-flg="true"> <a href="https://blog.csdn.net/Qgwperfect/article/details/83508772" target="_blank"> <h4 class="text-truncate oneline" style="width: 633px;"><em>BeanPostProcessor</em>的使用 - 早起的鸟儿有虫吃的博客 - CSDN博客</h4> <div class="info-box d-flex align-content-center"> <p> <span class="date">12-2</span> </p> </div> </a> </div>
08-14 阅读数 552
下面这个例子,是使用beanPostProcessor对不同值调用相同接口但不同实现的类Spring探秘|妙用BeanPostProcessor:https://www.jianshu.com/p/1... 博文 来自: 行简
08-10 阅读数 2万+
来源公众号:苦逼的码农作者:帅地前几天有个朋友去面试字节跳动,面试官问了他一道链表相关的算法题,不过他一时之间没做出来,就来问了我一下,感觉这道题还不错,拿来讲一讲。题目...... 博文 来自: WantFlyDaCheng的博客
04-12 阅读数 317
1.刷新容器2.在refresh()方法中 执行// Instantiate all remaining (non-lazy-init) singletons.// 初始化剩下的非延迟加载(non-l... 博文 来自: Thxxxxxx
<div class="recommend-item-box recommend-recommend-box"><div id="kp_box_61" data-pid="61"><script type="text/javascript">
(function() {
var s = "_" + Math.random().toString(36).slice(2);
document.write('<div style="" id="' + s + '"></div>');
(window.slotbydup = window.slotbydup || []).push({
id: "u3565309",
container: s
});
})();
10-22 阅读数 17万+
最近翻到一篇知乎,上面有不少用Python(大多是turtle库)绘制的树图,感觉很漂亮,我整理了一下,挑了一些我觉得不错的代码分享给大家(这些我都测试过,确实可以生成)one 樱花树 动态生成樱花效... 博文 来自: 碎片
01-06 阅读数 276
BeanPostProcessor的工作原理本次通过debug的方式追踪BeanPostProcessor的工作原理容器启动时的方法调用栈首先进入 AnnotationConfigApplicatio... 博文 来自: wmq930626的博客
09-15 阅读数 5万+
点击蓝色“五分钟学算法”关注我哟加个“星标”,天天中午 12:15,一起学算法作者 | 南之鱼来源 | 芝麻观点(chinamkt)所谓大企业病,一般都具有机构臃肿、多重...... 博文 来自: 程序员吴师兄的博客
11-21 阅读数 1361
一、先看下BeanPostProcessor和BeanFactoryPostProcessor的各自的子类以及方法。 1、 BeanFactoryPostProcessor,是针对整个工厂生产出... 博文 来自: leileibest_437147623的专栏
08-28 阅读数 371
在开发中经常遇到同一类似的处理,这一族类似的处理会根据不同的场景选择不同的处理类。例如,在报表生成中,需要生成交易明细日报,清算明细日报,挂账日报,积分月报等,这一族报表的处理都是类似的,也就... 博文 来自: qq_28060549的博客
<div class="recommend-item-box recommend-recommend-box"><div id="kp_box_62" data-pid="62"><script type="text/javascript">
(function() {
var s = "_" + Math.random().toString(36).slice(2);
document.write('<div style="" id="' + s + '"></div>');
(window.slotbydup = window.slotbydup || []).push({
id: "u3565311",
container: s
});
})();
09-05 阅读数 3万+
作为一个有着 8 年 Java 编程经验的 IT 老兵,说起来很惭愧,我被 Java 当中的四五个名词一直困扰着:**对象、引用、堆、栈、堆栈**(栈可同堆栈,因此是四个名词,也是五个名词)。每次我看... 博文 来自: 沉默王二
01-31 阅读数 257
根据Bean的生命周期中Spring创建Bean的过程,可知需要实现BeanPostProcessor接口首先创建一个测试用的类Car,并设置构造器方法,初始化方法public class Car {... 博文 来自: ChaunceyChen的博客
01-24 阅读数 2万+
引子Hacker(黑客),往往被人们理解为只会用非法手段来破坏网络安全的计算机高手。但是,黑客其实不是这样的,真正的“网络破坏者”是和黑客名称和读音相似的骇客。骇客,是用黑客手段进行非法操作并为己取得... 博文 来自: tiantian520ttjs——Python程序猿~
08-28 阅读数 8万+
文章目录0.新建操作:1.查看操作2.删除操作3.复制操作4.移动操作:5.重命名操作:6.解压压缩操作0.新建操作:mkdir abc #新建一个文件夹touch abc.sh #新建一个文件1.查... 博文 来自: 不能如期而至的专栏
06-23 阅读数 5万+
BeanPostProcessor:bean后置处理器,bean创建对象初始化前后进行拦截工作的1、BeanFactoryPostProcessor:BeanFactory的后置处理器; 在Bea... 博文 来自: 最怕一生碌碌无为,还安慰自己平凡可贵
<div class="recommend-item-box recommend-recommend-box"><div id="kp_box_63" data-pid="63"><script async="async" charset="utf-8" src="https://shared.ydstatic.com/js/yatdk/3.0.1/stream.js" data-id="8935aa488dd58452b9e5ee3b44f1212f" data-div-style="width:100%;" data-tit-style="margin-bottom: 6px; font-size: 18px; line-height: 24px; color: #3d3d3d;display: inline-block;font-weight:bold;" data-des-style="font-size: 13px; line-height: 22px; white-space: normal; color: #999;" data-img-style="float:left;margin-right:15px;width:90px;height:60px;" data-is-handling="1">
07-21 阅读数 29
“对于Spring框架,现实公司使用的非常广泛,但是由于业务的复杂程度不同,了解到很多小伙伴们利用Spring开发仅仅是利用了Spring的IOC,即使是AOP也很少用,但是目前的Spring是一个大... 博文 来自: qq_37670707的博客
10-25 阅读数 4万+
文章目录前言一、nginx简介1. 什么是 nginx 和可以做什么事情2.Nginx 作为 web 服务器3. 正向代理4. 反向代理5. 动静分离6.动静分离二、Nginx 的安装三、 Ngin... 博文 来自: 冯安晨
07-14 阅读数 286
Spring创建bean是根据配置来的,你可以通过xml文件配置,也可以通过java 的方式来配置,Spring在IOC容器完成bean的实例化、配置和初始化后可以通过BeanPostProcesso... 博文 来自: lby0307
01-08 阅读数 16万+
在博主认为,对于入门级学习java的最佳学习方法莫过于视频+博客+书籍+总结,前三者博主将淋漓尽致地挥毫于这篇博客文章中,至于总结在于个人,实际上越到后面你会发现学习的最好方式就是阅读参考官方文档其次... 博文 来自: 程序员宜春的博客
<div class="recommend-item-box recommend-recommend-box"><div id="kp_box_64" data-pid="64"><script async="async" charset="utf-8" src="https://shared.ydstatic.com/js/yatdk/3.0.1/stream.js" data-id="8935aa488dd58452b9e5ee3b44f1212f" data-div-style="width:100%;" data-tit-style="margin-bottom: 6px; font-size: 18px; line-height: 24px; color: #3d3d3d;display: inline-block;font-weight:bold;" data-des-style="font-size: 13px; line-height: 22px; white-space: normal; color: #999;" data-img-style="float:left;margin-right:15px;width:90px;height:60px;" data-is-handling="1">
05-12 阅读数 5949
BeanPostProcessors在spring中是一个非常重要的扩展接口,它使得我们可以在创建bean实例的前后做一些自己的处理;接下来我们就从源码层面来分析一下它是如何发挥作用的;一、bean的... 博文 来自: 石臻臻
10-13 阅读数 2999
需要数据库表1.学生表Student(SID,Sname,Sage,Ssex) --SID 学生编号,Sname 学生姓名,Sage 出生年月,Ssex 学生性别2.课程表Course(CID,Cna... 博文 来自: feifei_Tang的博客
09-20 阅读数 10万+
点击上面↑「爱开发」关注我们每晚10点,捕获技术思考和创业资源洞察什么是ThreadLocalThreadLocal是一个本地线程副本变量工具类,各个线程都拥有一份线程私...... 博文 来自: 爱开发
10-29 阅读数 187
转自 https://www.cnblogs.com/jyyzzjl/p/5417418.html一、接口描述spring提供了一个接口类-BeanPostProcessor,我们叫他:bean的... 博文 来自: 早起的鸟儿有虫吃的博客
11-13 阅读数 2万+
作者 | Google团队译者 | 凯隐编辑 | Jane出品 | AI科技大本营(ID:rgznai100)本文中,Google 团队提出了一种文本语音合成(text to speech)神经系统,... 博文 来自: AI科技大本营
<div class="recommend-item-box recommend-recommend-box"><div id="kp_box_65" data-pid="65"><script async="async" charset="utf-8" src="https://shared.ydstatic.com/js/yatdk/3.0.1/stream.js" data-id="8935aa488dd58452b9e5ee3b44f1212f" data-div-style="width:100%;" data-tit-style="margin-bottom: 6px; font-size: 18px; line-height: 24px; color: #3d3d3d;display: inline-block;font-weight:bold;" data-des-style="font-size: 13px; line-height: 22px; white-space: normal; color: #999;" data-img-style="float:left;margin-right:15px;width:90px;height:60px;" data-is-handling="1">
10-22 阅读数 728
点击蓝色“沉默王二”关注我哟今天迟到了,非常抱歉,让大家久等了。01、开门见山由于我比较喜欢分享的原因,认识了不少大学生。其中有不少佼佼者,比如说一年读 50 本书的璐璐...... 博文 来自: 代码GG陆晓明
10-26 阅读数 1089
面试必问,面试必问,面试必问!别问我为什么知道~~总结run()只是Thread类的一个普通方法,调用run()并不会新建一个子线程,仍在主线程执行任务。调用start()会新建一个子线程并执行run... 博文 来自: joy_pan的博客
11-17 阅读数 1万+
实时采集并分析Nginx日志, 自动化封禁风险IP方案文章地址: https://blog.piaoruiqing.com/2019/11/17/block-ip-by-analyzing-nginx... 博文 来自: 草堂笺
10-19 阅读数 1831
这是两种以跨平台为特色的开发方式。Qt更多被认为是一种框架,但是Qt中有新增一些C++所没有的语法,所以也可以认为是一种编程语言。Java被认为是一种编程语言,但是很多人并不知道JAVA的编程语言其实... 博文 来自: rediculous的专栏
01-06 阅读数 19
最近想对项目中的所有bean进行一个代理。然后监控bean得方法的使用情况。 刚开始想的方法是:重写项目的beanFactory,然后再getBean的使用,对结果object进行一个代理,达到我... 博文 来自: weixin_34224941的博客
<div class="recommend-item-box recommend-recommend-box"><div id="kp_box_66" data-pid="66"><script type="text/javascript">
(function() {
var s = "_" + Math.random().toString(36).slice(2);
document.write('<div style="" id="' + s + '"></div>');
(window.slotbydup = window.slotbydup || []).push({
id: "u4623747",
container: s
});
})();
05-16 阅读数 2464
位算法的效率有多快我就不说,不信你可以去用 10 亿个数据模拟一下,今天给大家讲一讲位运算的一些经典例子。不过,最重要的不是看懂了这些例子就好,而是要在以后多去运用位运算这些技巧,当然,采用位运算,也... 博文 来自: weixin_34014555的博客
搞学习
知乎:www.zhihu.com
大学资源网:http://www.dxzy163.com/
简答题:http://www.jiandati.com…
博文
这篇文章很长,但绝对是精华,相信我,读完以后,你会知道学历不好的解决方案…
博文
<div class="recommend-item-box recommend-recommend-box"><div><iframe width="962" frameborder="0" height="52" scrolling="no" src="//pos.baidu.com/s?hei=52&wid=962&di=u3491668&ltu=https%3A%2F%2Fblog.csdn.net%2Fzwjyyy1203%2Farticle%2Fdetails%2F89576084&psi=2e6a1c7223c2ef589ede851279a4bbb2&dis=0&dc=3&cpl=3&cfv=0&ant=0&pcs=1215x564&ti=BeanPostProcessor%E5%A6%99%E7%94%A8%EF%BC%88%E8%BD%AC%E8%BD%BD%EF%BC%89&dtm=HTML_POST&tcn=1580884794&pss=1230x9007&cec=UTF-8&psr=1536x864&dai=6&cdo=-1&ccd=24&tpr=1580884793781&col=zh-CN&drs=3&par=1536x824&ari=2&cce=true&prot=2&cja=false&ps=6023x383&dri=1&cmi=4&pis=-1x-1&exps=111000,110011&tlm=1580884793&chi=2"></iframe></div><script type="text/javascript" src="//rabc1.iteye.com/production/res/rxjg.js?pkcgstj=jm"></script></div>
补充
有不少读者留言说本文章没有用,因为天气预报直接打开手机就可以收到了,为何要多此一举发送到邮箱呢!!!…
博文
11-04 阅读数 2万+
文章目录博客说明:基础知识 001.Hello,WorldPython2.7能够正常输出py2、py3Python3.7无法正常输出py2,版本不兼容 0... 博文
11-18 阅读数 7万+
11月8日,由中国信息通信研究院、中国通信标准化协会、中国互联网协会、可信区块链推进计划联合主办,科技行者协办的2019可信区块链峰会将在北京悠唐皇冠假日酒店开幕。
区块链技术被认为…
博文
11-18 阅读数 8921
不知觉已中码龄已突破五年,一路走来从起初铁憨憨到现在的十九线程序员,一路成长,虽然不能成为高工,但是也能挡下一面,从15年很火的android开始入坑,走过java、.Net、QT,目前仍处于... 博文
<div class="recommend-item-box recommend-recommend-box"><div><iframe width="962" frameborder="0" height="52" scrolling="no" src="https://pos.baidu.com/s?hei=52&wid=962&di=u3491668&ltu=https%3A%2F%2Fblog.csdn.net%2Fzwjyyy1203%2Farticle%2Fdetails%2F89576084&psi=2e6a1c7223c2ef589ede851279a4bbb2&tpr=1580884793781&tlm=1580884793&dtm=HTML_POST&prot=2&cce=true&tcn=1580884794&pcs=1215x564&cpl=3&cdo=-1&ccd=24&exps=111000,110011&chi=2&dri=2&par=1536x824&psr=1536x864&dis=0&cja=false&dai=7&dc=3&col=zh-CN&cmi=4&ps=6487x383&pss=1230x9065&cec=UTF-8&drs=3&ant=0&cfv=0&ti=BeanPostProcessor%E5%A6%99%E7%94%A8%EF%BC%88%E8%BD%AC%E8%BD%BD%EF%BC%89&ari=2&pis=-1x-1"></iframe></div><script type="text/javascript" src="//rabc1.iteye.com/production/res/rxjg.js?pkcgstj=jm"></script></div>
作者 | 胡书敏
责编 | 刘静
出品 | CSDN(ID:CSDNnews)
本人目前在一家知名外企担任架构师,而且最近八年来,在多家外企和互联网公司担任Java技术面试官…
博文
作者 | 许向武
责编 | 屠敏
出品 | CSDN 博客
前言
在 Python 进阶的过程中,相信很多同学应该大致上学习了很多 Python 的基础知识,也正在努力成长。在此…
博文
一、什么是中台?
这其实是一个老生常谈的概念了,中台,顾名思义,就是在起中间作…
博文
上面是一个读者“烦不烦”问我的一个问题。其实不止是“烦不烦”,还有很多读者问过我类似这样的问题。
我接的私活不算多,挣到…
博文
11-25 阅读数 7万+
今年正式步入了大四,离毕业也只剩半年多的时间,回想一下大学四年,感觉自己走了不少弯路,今天就来分享一下自己大学的学习经历,也希望其他人能不要走我走错的路。
(一)初进校园
刚进入大学的时候自己完全…
博文
一、前言
二、redis基础知识
2.1 从“处理器-缓存-内存”到“后台-redis-数据库”
2.2 不使用缓存与使用缓存(读操作+写操作)
2.3 redis典型问题:缓存穿透…
博文
不要白嫖请点赞
不要白嫖请点赞
不要白嫖请点赞
文中提到的书我都有电子版,可以评论邮箱发给你。
文中提到的书我都有电子版,可以评论邮箱发给你。
文…
博文
istream:输入流类型,提供输入操作。
ostream:输出流类型,提供输出操作。
cin:istream对象,从标准输入读取数据。
cout:ostream对…
博文
出品 | CSDN(ID:CSDNnews)
世界500强中,30%的掌舵人,都是印度人。
是的,你没看错。这是近日《哈佛商业评论》的研究结果。
其中又以微软CEO萨提亚·纳…
博文
在邂逅了完线性结构的数组和队列后, 我们便偶遇了栈这个东东, 他到底是个啥?
就让我们慢慢揭开它的神秘面纱吧~~~
需求介绍
栈的介绍
栈的英文为(stack)
栈是一个先入后出(FILO…
博文
基本情况:
专业技能:
1、 熟悉Sping了解SpringMVC、S…
博文
HelloGitHub
star:19k
Python,Java,PHP,C++,go…
博文
前言:
禅道
Jenkins
sonarqube
4.showdoc
5.swgger
6.分布式配置中心apollo
8.项目开发…
博文
01-24 阅读数 5053
请允许我用22种编程语言,祝大家新年快乐 C语言:printf(“祝大家新年快乐”); C++ : cout<<“祝大家新年快乐”; OC: NSLog(@“祝大家新年快乐”) Q... 博文
01-27 阅读数 2万+
很遗憾,这个春节注定是刻骨铭心的,新型冠状病毒让每个人的神经都是紧绷的。那些处在武汉的白衣天使们,尤其值得我们的尊敬。而我们这些窝在家里的程序员,能不外出就不外出,就是对社会做出的最大的贡献。
有些…
博文
02-01 阅读数 4716
man: Manual 意思是手册,可以用这个命令查询其他命令的用法。 pwd:Print working directory 意思是密码。 su:Swith user 切换用户,切换到ro... 博文
01-30 阅读数 1万+
返回json示例 { "errcode":0,//0标识接口正常 "data":{ "date":"2020-01-30 07:47:23",//实时更新时间 ... 博文
抓取每个城市的当前感染数据
导入相关模块
import time
import json
import re…
博文
<div class="recommend-item-box type_hot_word"> <div class="content clearfix" style="width: 712px;"> <div class="float-left"> <span> <a href="https://blog.csdn.net/yilovexing/article/details/80577510" target="_blank"> python</a> </span> <span> <a href="https://blog.csdn.net/slwbcsdn/article/details/53458352" target="_blank"> json</a> </span> <span> <a href="https://blog.csdn.net/csdnnews/article/details/83753246" target="_blank"> java</a> </span> <span> <a href="https://blog.csdn.net/qq_35077512/article/details/88952519" target="_blank"> mysql</a> </span> <span> <a href="https://blog.csdn.net/pdcfighting/article/details/80297499" target="_blank"> pycharm</a> </span> <span> <a href="https://blog.csdn.net/sinyu890807/article/details/97142065" target="_blank"> android</a> </span> <span> <a href="https://blog.csdn.net/gexiaoyizhimei/article/details/100122368" target="_blank"> linux</a> </span> <span> <a href="https://download.csdn.net/download/xhg_gszs/10978826" target="_blank"> json格式</a> </span> <span> <a href="https://www.csdn.net/gather_16/NtzaUgzsLWRvd25sb2Fk.html" target="_blank"> c# ef通用数据层封装</a> </span> <span> <a href="https://www.csdn.net/gather_18/NtzaUg0sLWRvd25sb2Fk.html" target="_blank"> c# queu task</a> </span> <span> <a href="https://www.csdn.net/gather_1c/NtzaUg1sLWRvd25sb2Fk.html" target="_blank"> c# timeout单位</a> </span> <span> <a href="https://www.csdn.net/gather_12/NtzaUg2sLWRvd25sb2Fk.html" target="_blank"> c#中indexof(c</a> </span> <span> <a href="https://www.csdn.net/gather_14/NtzaUg3sLWRvd25sb2Fk.html" target="_blank"> c#常量定义规则</a> </span> <span> <a href="https://www.csdn.net/gather_1b/NtzaUg4sLWRvd25sb2Fk.html" target="_blank"> c#发送按键</a> </span> <span> <a href="https://www.csdn.net/gather_2f/NtzaUg5sLWJsb2cO0O0O.html" target="_blank"> c#记住帐号密码</a> </span> <span> <a href="https://www.csdn.net/gather_12/NtzaYgwsLWRvd25sb2Fk.html" target="_blank"> c#mvc框架搭建</a> </span> <span> <a href="https://www.csdn.net/gather_10/NtzaYgysLWRvd25sb2Fk.html" target="_blank"> c#改变td值</a> </span> <span> <a href="https://www.csdn.net/gather_1e/NtzaYgzsLWRvd25sb2Fk.html" target="_blank"> c#怎么读取html文件</a> </span> </div> </div> </div> <div class="recommend-loading-box"> <img src="https://csdnimg.cn/release/phoenix/images/feedLoading.gif"> </div> <div class="recommend-end-box" style="display: block;"> <p class="text-center">没有更多推荐了,<a href="https://blog.csdn.net/" class="c-blue c-blue-hover c-blue-focus">返回首页</a></p> </div> </div> <div class="template-box"> <span>©️2019 CSDN</span><span class="point"></span> <span>皮肤主题: 大白</span> <span> 设计师: CSDN官方博客 </span> </div> </main>@[TOC](这里写自定义目录标题)
你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。
我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:
撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G
直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC
语法后生成一个完美的目录。
强调文本 强调文本
加粗文本 加粗文本
标记文本
删除文本
引用文本
H2O is是液体。
210 运算结果是 1024.
链接: link.
图片:
带尺寸的图片:
居中的图片:
居中并且带尺寸的图片:
当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。
去博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片
.
// An highlighted block
var foo = 'bar';
一个简单的表格是这么创建的:
项目 | Value |
---|---|
电脑 | $1600 |
手机 | $12 |
导管 | $1 |
使用:---------:
居中
使用:----------
居左
使用----------:
居右
第一列 | 第二列 | 第三列 |
---|---|---|
第一列文本居中 | 第二列文本居右 | 第三列文本居左 |
SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:
TYPE | ASCII | HTML |
---|---|---|
Single backticks | 'Isn't this fun?' | ‘Isn’t this fun?’ |
Quotes | "Isn't this fun?" | “Isn’t this fun?” |
Dashes | -- is en-dash, --- is em-dash | – is en-dash, — is em-dash |
一个具有注脚的文本。2
Markdown将文本转换为 HTML。
您可以使用渲染LaTeX数学表达式 KaTeX:
Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n−1)!∀n∈N 是通过欧拉积分
Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=∫0∞tz−1e−tdt.
你可以找到更多关于的信息 LaTeX 数学表达式here.
可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图:
这将产生一个流程图。:
我们依旧会支持flowchart的流程图:
如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。
如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。
注脚的解释 ↩︎
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。