整合营销网站,百度搜索引擎属于什么引擎,电商平台网站制作费用,中小网站 架构[spring] spring core - 配置注入及其他内容补充
上篇 [sping] spring core - 依赖注入
这里主要补一些 core 相关内容补充#xff0c;同时添加了 java config bean 的方法
java config bean 是除了 XML、java 注解之外另一给实现 DI 的方法
java config bean
这个方法不…[spring] spring core - 配置注入及其他内容补充
上篇 [sping] spring core - 依赖注入
这里主要补一些 core 相关内容补充同时添加了 java config bean 的方法
java config bean 是除了 XML、java 注解之外另一给实现 DI 的方法
java config bean
这个方法不使用 annotation而是使用 Configure 类实现
首先实现一个不使用注解的类
package com.example.demo;public class Lambda implements DBConnection{Overridepublic String connect() {return Connection via Lambda;}
}
将这个类注入到 controller 的过程为 创建 Configure 类 package com.example.demo;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;Configuration
public class DBConfig {
} 定义 Bean 方法去配置 bean
Configuration
public class DBConfig {Beanpublic DBConnection lambdaConn() {return new Lambda();}
} bean id 默认为方法名 将 bean 注入到 controller 这里依旧使用 Qualifier(lambdaConn) 去实现 RestController
public class FirstRestController {private DBConnection dbconn;Autowiredpublic void setDBconn(Qualifier(lambdaConn) DBConnection dbconn) {System.out.println(dbconn from setter);this.dbconn dbconn;}}效果如下
java config bean vs annotation
二者的优缺点还是比较明显的
方法优点缺点注解简单 boilerplate 代码少 直观 难以溯源尤其是当代码量大起来的时候寻找对应的依赖会比较困难 耦合度较高java-based-config集中配置灵活性尤其是对接第三方代码或是 legacy 代码低耦合boilerplate 代码较多学习曲线更为陡峭
一般推荐方案有
中小型项目代码量较少的情况下使用注解中大型项目使用 java 配置在有需求的时候进行混用特别是对于无法控制的第三方库或是一时半会儿没法重构的代码考虑使用 spring profile Profile 代替 java config
component scan
关于 component scanspring 会扫面 entry point——即有 SpringBootApplication 的 java class——的统计和子 package如果结构更新成下面这样的 那 util 中的 class 不会被 spring 自动扫到: 想要让 spring 扫到 util 下的代码需要使用在 SpringBootApplication 中添加 scanBasePackages如
SpringBootApplication(scanBasePackages {com.example.util})
public class DemoApplication {// ...
}除了有 scanBasePackages 之外还有 scanBasePackageClasses
懒初始化
在 spring 项目启动时所有的 bean 默认都完成初始化。我在构造函数里面添加了一行 System.out.println(In constructor: getClass().getSimpleName()); 后终端显示如下 可以看到在 LiveReload 和 Tomcat 启动之前所有的 bean 都完成了实例化。
这也就意味着项目在启动初期一定会更加耗时想要对其优化可以使用懒初始化lazy initialization。这样 bean 只有在这两个情况下会被初始化
被其他的 bean 进行调用直接请求当前 bean
实现的方法有三种 全局化实现 这个在 spring boot 中的配置文件如 application.properties 中实现 spring.main.lazy-initializationtrue使用 Lazy 注解 这个又可以分成多种情况 直接使用 Component 的可以在 Component 中加 ComponentLazypublic class MySQL implements DBConnection {} 这时候 MySQL 就不会显示完成加载 Java Config 中可以在对应的 bean 上加如 Configurationpublic class DBConfig {BeanLazypublic DBConnection lambdaConn() {return new Lambda();}BeanLazypublic DBConnection mongoDBConn() {return new MongoDB();}} 我这里添加了一个 MongoDB因为 lambdaConn 在启动 rest controller 时被请求所以肯定是要实例化才能进行下一步的。 改完后效果如下 在被 Autowired 地方的添加 Lazy RestController
public class FirstRestController {private DBConnection dbconn;AutowiredLazypublic void setDBconn(Qualifier(lambdaConn) DBConnection dbconn) {System.out.println(dbconn from setter);this.dbconn dbconn;}} 这个情况下只有当该 rest controller 被访问时才会进行初始化 JDBC 是唯一一个没有被添加 Lazy 的类因此一开始它就被初始化了 随后可以看到尽管这里用的是 setter 注入但是却没有对象被实例化一直到服务器启动了网页被访问之后Lambda 对象才被实例化 XML 中也可以添加 lazy-init 属性实现不过我这没 XML 的案例就不贴代码了
总体来说懒初始化可以提升项目启动速度不过这个成本可能会加到运行的时候因此在做优化时还是要跑一些 metrics 去最终决定是否要实现懒初始化或是哪些 bean 被懒初始
bean 生命周期
上网找了一下大体的流程是这样的 不过教程没有细说之时提了两个比较常用的 lifecycle callbackinit 和 cleanup。前者在 bean 准备被使用前调用这里可以处理一些 side effect如链接 db新建 socket 等后者则是在 bean 被销毁前调用用来清理一些 side effect
init
有三种方式可以实现 XML bean idsomeBeanId classsome.class init-methodmethod-name /注解 public class MySQL implements DBConnection {PostConstructpublic void init() {// init logic}
}通过实现 InitializingBean 进行重载 public class MySQL implements DBConnection, InitializingBean {Overridepublic void afterPropertiesSet() throws Exception {}
}cleanup
也是三种实现方式
XML
bean idsomeBeanId classsome.class destroy-methodmethod-name /注解 public class MySQL implements DBConnection {PreDestroypublic void cleanup() {// clean up logic}
}实现 interface public class MySQL implements DBConnection, DisposableBean {Overridepublic void destroy() throws Exception {}
}bean scope
bean scope 和它的生命周期以及在 app 中的可见度即被分享有关所有的 bean 默认都是 singleton。
目前官方提供的列表为
scope描述singleton默认每个 IoC 容器只会生成一个prototype每次容器新创建一个对象就就会新创建一个 instancerequest每个 HTTP 请求会生成一个新的 instance 只有在 web 项目中适用session每个 HTTP session 中会生成一个 instance 只有在 web 项目中适用application每个 ServletContext 生命周期会生成一个 instance 只有在 web 项目中适用 网页项目中与 singleton 相似websocket同理一个 websocket 生命周期中会生成一个 instance 只有在 web 项目中适用
XML 中的配置方法为
bean idsomeBeanId classsome.class scopea_valid_scope /使用 annotation 的方式为
Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Lambda implements DBConnection{// ...
}
这里简单的进行一下 shallow compare即对比地址
public class FirstRestController {private DBConnection dbconn;private DBConnection dbconn2;Autowiredpublic void setDBconn(Qualifier(lambdaConn) DBConnection dbconn, Qualifier(lambdaCoÏnn) DBConnection dbconn2) {System.out.println(dbconn from setter);this.dbconn dbconn;this.dbconn2 dbconn2;}GetMapping(/check)public String getCheck() {System.out.println(dbconn.getClass().getSimpleName());return Comparing beans: dbconn (this.dbconn2 this.dbconn ? : !) dbconn2.;}
}
在 prototype 的情况下为 false 在默认singleton的情况下为 true 特殊的 prototype
prototype 的清理有一些特殊因为 spring 不会对 prototype 的生命周期进行完整的干里即不会调用对应的清理函数所以如果某个 bean 需要经常被创建/毁灭那么就要考虑是不是需要使用 prototype还是应该使用其他的 scope
以及prototype bean 默认就是懒初始化所以没有必要添加 Lazy
总结