网络知识 娱乐 Spring、 IoC 容器和静态代码设计原则

Spring、 IoC 容器和静态代码设计原则

{"data":{"title":"Spring、 IoC 容器和静态代码设计原则","abstract":"控制反转模式,IoC 框架内的静态代码(比如 spring) ,以及 IoC 框架内的静态代码中连接实用方法的问题在本文中,我将讨论控制反转模式、 IoC 框架(比如 spring)中的静态代码(可以是遗留代码,也可以是新创建的代码) ,以及 IoC 框架中静态代码中的连接实用程","cover":"https://p3.toutiaoimg.com/origin/tos-cn-i-qvj2lq49k0/2b4fbdf722684ecf962c9a0959aa7ab0","articleType":"article","itemId":"7112657943958536712","groupId":"7112657943958536712","groupSource":2,"isOriginal":true,"banComment":false,"publishTime":"2022-06-24 12:29","source":"qaseven","tag":"technique","mediaSite":null,"pathname":"/article/7112657943958536712/","loginUserInfo":null,"favorite":false,"relation":{"isFollowing":false,"isFollowed":false},"likeData":{"userLikeStatus":0,"count":0},"isSelf":false,"content":"

控制反转模式,IoC 框架内的静态代码(比如 spring) ,以及 IoC 框架内的静态代码中连接实用方法的问题


在本文中,我将讨论控制反转模式、 IoC 框架(比如 spring)中的静态代码(可以是遗留代码,也可以是新创建的代码) ,以及 IoC 框架中静态代码中的连接实用程序方法。

静态方法

例如,我们有一个 HttpUtils 类,其中包含许多静态方法。我们是否应该删除 static 关键字并用 Spring 原型注释该类,这会立即将其转换为 Spring 单例模式?

在 java 中,static 关键字表示成员或方法属于类型本身,而不是该类型的实例。这意味着只创建这个静态成员的一个实例,并且它在类的所有实例之间共享; 如果它是 IoC 框架内的一个静态方法,这意味着该方法的运行方式对于这个类和这个方法的所有用法都是唯一的。在这种情况下,有三种可能性:

  1. 该方法不修改上下文数据(由应用程序处理的数据)。所以我们可以认为,尽管它是静态的,但它是线程安全的
  2. 该方法修改上下文数据,因此它是线程不安全的
  3. 该方法修改上下文数据,但是它是线程安全的,因为它是“同步的”(一次执行一个执行) ,这会严重影响性能

Java 中提供的静态方法与构建时一样。这就是为什么它们永远不可能超载。因此,抽象方法不能是静态的,它们不能访问类或上下文值而不作为参数传递(不能访问 this 或 super)。

那么静态代码适用于“ Utils”类吗?是的,因为我们在案例1中,将不会有来自上下文的修改数据,输入将被转换为输出,并且作为一般规则,这种类可以导出,而不管上下文如何。但是,如果它是可导出的,那么这些代码不应该直接存在于所有项目都可以使用的库中吗?是的,跨职能团队会很高兴定期收到来自团队的贡献,这些团队考虑将实用代码提供给不需要上下文的每个人。

静态代码适用于其他任何情况吗? 如果有更好的办法,就不适用。

可用于弹簧的作用域

范围

描述

singleton

这将 bean 定义的范围扩展到每个 Spring IoC 容器(默认)的一个实例

prototype

.这将单个 bean 定义的范围扩展为具有任意数量的对象实例

request

这将 bean 定义的范围扩展到 HTTP 请求。只有在支持 Web 的 SpringApplicationContext 上下文中才有效

session

这将 bean 定义的范围扩展到 HTTP 会话。只有在支持 Web 的 SpringApplicationContext 上下文中才有效

全球会议

这将 bean 定义的范围扩展到全局 HTTP 会话。只有在支持 Web 的 SpringApplicationContext 上下文中才有效

Singletons

如果范围被设置为 Singleton,那么 Spring IoC 容器将创建由 bean 定义定义的对象的一个实例。这个单一实例存储在这些单一 bean 的缓存中,对这个 bean 的所有后续请求和引用都返回缓存中的对象。

该引擎管理任何缓存、过期和 bean 的再生(如果从库存中取出的话)。如果 bean 没有更多状态或没有状态,则可能出现缓存出口。

例如,在调用 httpsUtils.callUrl ()时,容器必须决定是重用已实例化的 bean 还是创建新的 bean。集装箱如何决定?当在容器中(在框架上)注册 bean httpUtils 时,可以向这个容器指出我们希望它如何工作。此外,第一个实例可以在应用程序开始时创建,也可以在对 bean 的第一次调用时创建。也就是说,bean 调用方不必知道 bean 的生命周期; 它们调用 httpUtils.callUrl ()。

这是在包含大量类和每个类的方法的应用程序中提供类方法的最佳方法。

因此,我们有一个第一个(全局)性能参数来将所有静态方法转换为单例,以便从 Spring IoC 缓存中获益。访问静态方法在理论上更快,因为 JVM 在执行之前不需要查找函数,但在实践中,大多数 JDK 都优化了实例方法调用。也就是说,当涉及到性能时,最常见的原因是糟糕的设计。如果静态代码更快,那么我们可以用静态代码来编写整个应用程序; 既然模式和静态代码可以做同样的工作,但是它们的构造不同,为什么还要按 IoC 模式声明类和方法呢?

如果我们再次以 HttpUtils 类为例,使用静态代码的原则是我可以直接从该类访问 callUrl ()方法; 我们将 callUrl ()的定义及其实现结合在一起。IoC 努力分离这种细节,因此,我们在接口中定义一个方法。例如,这允许通过几个实现来拒绝这个接口。HttpUtils 的接口实现将成为 HttpUtils 的配置。注意,使用 HttpUtils 的类不知道 callUrl ()的执行范围,因为框架中使用的范围也依赖于配置。

总之,IoC 和 static 通常是不一致的。IoC 促进变化,而静态,根据定义,阻止变化。根据框架注入您的依赖项,您将看到您可以完全免除使用静态特性。

Security

还有一个理由: spring bean的所有成员都应该被inject(cf https://rules.sonarsource.com/java/type/vulnerability/rspec-3749) :

Vulnerability: CriticalnnspringnnowaspnnSpring @Component, @Controller, @Service, and @Repository classes are singletons by default, meaning only one instance of the class is ever instantiated in the application. Typically such a class might have a few static members, such as a logger, but all non-static members should be managed by Spring. That is, they should have one of these annotations: @Resource, @Inject, @Autowired or @Value.nnHaving non-injected members in one of these classes could indicate an attempt to manage state. Because they are singletons, such an attempt is almost guaranteed to eventually expose data from User1's session to User2.


当一个未用@ConfigurationProperties 进行注释的 singleton@Component、@Controller、@Service 或@Repository 拥有非静态成员,而这些成员未用以下方式之一进行注释时,该规则会引发一个问题:

  • org.springframework.beans.factory.annotation.Autowired
  • org.springframework.beans.factory.annotation.Value
  • javax.annotation.Inject
  • javax.annotation.Resource

不符合规范的代码

@Controllernpublic class HelloWorld {n private String name = null;n @RequestMapping("/greet", method = GET)n public String greet(String greetee) {n if (greete != null) {n this.name = greetee;n }n return "Hello " + this.name; // if greetee is null, you see the previous user's datan }nn}


String 是一个类,涉及到任何类,包括那些包含将在 Spring bean 中调用的静态方法的类。



","imageList":[],"mediaInfo":{"userId":"MS4wLjABAAAA8-6yry9XXyfX7z4WXHRyv9hzDr8Dx8oFTW5HLX2jb6g","unsafeUserId":"70547627105","name":"qaseven","avatarUrl":"https://p3.toutiaoimg.com/origin/tos-cn-i-jcdsk5yqko/fe89d0f5470e4967ae83a0f26c3e3aef","description":"测试专家,擅长敏捷测试,自动化测试,devops等领域","userVerified":1},"seoTDK":{"title":"Spring、 IoC 容器和静态代码设计原则-今日头条","description":"控制反转模式,IoC 框架内的静态代码(比如 spring) ,以及 IoC 框架内的静态代码中连接实用方法的问题在本文中,我将讨论控制反转模式","keywords":"设计,Java,Java虚拟机,新创建集团","publishTimestamp":"1656044946","modifiedTimestamp":"1656046157"},"logId":"202206241419080101581201440796D88C","sylpageConfig":{"card":{"id":""}},"identity":{"web_id":"7111199547455817229","user_is_login":false},"abtestInfo":{"rsp_type":5,"version_name":"4252807,4164637","parameters":{"feat_repost_type":{"new":true},"home_nav_conf":{"dcd_out":1},"local_filter":{"core_filter":{"filter_list":{"ms::TicaiFilter":true}}},"page_upgrade":{"new_profile":true,"video_double_column":true},"sati":{"enable_ad_prime":true,"enable_sorter_optimus":true,"prime_rule_rank_version":"toutiao_web","use_toutiao_web_feed":true,"format_max_consecutive_middle":2,"format_max_consecutive_nogroups":3,"enable_reduce_nogroup":true},"seraph":{"score_rule":{"default":{"replace":{"group_util":"_CTR - 1000*dislike"}},"new_user":{"replace":{"group_util":"_CTR - 1000*dislike"}}}},"sort":{"allowed_ticai":["forum_post","pgc_text","pgc_video"]},"video_detail_page_upgrade":{"new_page":true}},"env_flag":0},"localCityInfo":{"name":"北京","code":"110000","channelId":3202164529},"showResearch":false}}