资讯专栏INFORMATION COLUMN

〔SPRING FRAMEWORK〕Dependencies

MonoLog / 1200人阅读

摘要:每个属性参数构造函数中值的类型都能够被成字符串类型。对比上文给出的个代码片段,可发现皆在用不同的方法进行元数据配置,并且被配置的具体对象是数据库驱动。

@(SPRING FRAMEWORK)

〔4〕7.4 Dependencies

声明:

斜体字:《官档》原文

斜体加粗字:《官档》原文的重点字、词、句

正体字+前置〔〕:个人表述行为,如:〔总结〕、〔分析〕等

灰体字:生词

粉体字:疑问

[TOC]

A typical enterprise application does not consist of a single object
〔总结〕一个典型的程序,是需要多个对象相互协作

how you go from defining a number of bean definitions that stand alone to a fully realized application where objects collaborate to achieve a goal.
〔总结〕定义一群具备相互协作能力的对象,以实现目标程序

1. Dependency Injection

Dependency injection (DI):is a process whereby objects define their dependencies, that is, the other objects they work with, only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse, hence the name Inversion of Control (IoC), of the bean itself controlling the instantiation or location of its dependencies on its own by using direct construction of classes, or the Service Locator pattern.

1.1 Constructor-based dependency injection

关键词:

Constructor-based DI is accomplished by the container invoking a constructor with a number of arguments, each representing a dependency.

Calling a static factory method with specific arguments to construct the bean is nearly equivalent, and this discussion treats arguments to a constructor and to a static factory method similarly.

示例代码

public class SimpleMovieLister {

    // the SimpleMovieLister has a dependency on a MovieFinder
    private MovieFinder movieFinder;

    // a constructor so that the Spring container can inject a MovieFinder
    public SimpleMovieLister(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // business logic that actually uses the injected MovieFinder is omitted...

}

〔总结〕基于构造函数的依赖注入,其核心在构造函数上,即重点需要放在一个疑问点上:构造函数如何影响依赖注入(依赖注入的成功标准:一个bean对象已完成实例化)?

一个规范:顺序

示例代码

package x.y;

public class Foo {

    public Foo(Bar bar, Baz baz) {
        // ...
    }

}

第1种bean引用方式:引用引用类型

〔注意〕bean引用方式是指:容器在实例化化一个bean时,需要读取配置元数据。因为配置元数据中包含了可实例化一个POJO对象的所有必要数据



    
    
        
        
    

    

    

第2种bean引用方式:引用基本数据类型

package examples;

public class ExampleBean {

    // Number of years to calculate the Ultimate Answer
    private int years;

    // The Answer to Life, the Universe, and Everything
    private String ultimateAnswer;

    public ExampleBean(int years, String ultimateAnswer) {
        this.years = years;
        this.ultimateAnswer = ultimateAnswer;
    }

}

基于type属性



    
    

基于name属性



    
    

基于index属性



    
    
1.2 Setter-based dependency injection

关键词: no-argument

〔总结〕符合以下任一点,可选择基于setter的依赖注入

无参构造函数

无参工厂方法

public class SimpleMovieLister {

    // the SimpleMovieLister has a dependency on the MovieFinder
    private MovieFinder movieFinder;

    // a setter method so that the Spring container can inject a MovieFinder
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // business logic that actually uses the injected MovieFinder is omitted...

}

〔总结〕对比基于带参构造函数依赖注入和基于setter依赖注入,可以发现:基于构造函数的不需要提供setter/getter,基于setter的不需要提供带参构造函数

Q: Constructor-based or setter-based DI?

Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies. Note that use of the @Required annotation on a setter method can be used to make the property a required dependency.

可以混搭一起用。根据实际开发经验,以Constructor-based DI为主,以setter-based DI为辅。主是强制,辅是可选。

The Spring team generally advocates constructor injection as it enables one to implement application components as immutable objects and to ensure that required dependencies are not null. Furthermore constructor-injected components are always returned to client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.

Constructor-based DI能确保

Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is therefore a compelling use case for setter injection.

Use the DI style that makes the most sense for a particular class. Sometimes, when dealing with third-party classes for which you do not have the source, the choice is made for you. For example, if a third-party class does not expose any setter methods, then constructor injection may be the only available form of DI.

〔总结〕懵逼¬_¬

1.3 Dependency resolution process

〔总结〕执行注入的步骤(详见《官档》):

ApplicationContext根据配置元数据装配所有bean对象

当依赖的具体表现形式为以下时:

properties

constructor arguments

arguments to the static-factory method
那么ApplicationContext会根据配置元数据的信息为POJO对象引用到对应的bean对象上。

要保证在每个属性,参数构造函数能设值的时候,必须提供值,这个值:可以是基本值,也可以是引用值。

每个属性、参数构造函数中值的类型都能够被Spring convert成字符串类型。

如何解决Circular dependencies ?

Circular dependencies场景

Class A requires an instance of class B through constructor injection, and class B requires an instance of class A through constructor injection.

If you configure beans for classes A and B to be injected into each other, the Spring IoC container detects this circular reference at runtime, and throws a BeanCurrentlyInCreationException.

Circular dependencies异常解决方案:
you can configure circular dependencies with setter injection.

1.4 Examples of dependency injection

代码案例:参见《官档》

2. Dependencies and configuration in detail 2.1 Straight values

观察以下三个代码片段:

代码片段 1 使用最原始的方式


    
    
    
    
    

代码片段 2 : 使用p-namespace配置元数据



    

代码片段 3:使用java.util.Properties



    
    
        
            jdbc.driver.className=com.mysql.jdbc.Driver
            jdbc.url=jdbc:mysql://localhost:3306/mydb
        
    

〔总结〕
1. 阅读对应《官档》后,依旧对小标题#Straight values#的具体含义模糊不清,不清楚其牵引下文的意图是什么。
2. 对比上文给出的3个代码片段,可发现:皆在用不同的方法进行元数据配置,并且被配置的具体对象是数据库驱动

2.2 References to other beans

关键词:ref

The ref element is the final element inside a or definition element.Here you set the value of the specified property of ③ a bean to be a reference to another bean (a collaborator) managed by the container. The referenced bean is a dependency of the bean whose property will be set, and it is initialized on demand as needed before the property is set. (If the collaborator is a singleton bean, it may be initialized already by the container.) All references are ultimately a reference to another object. Scoping and validation depend on whether you specify the id/name of the other object through the bean, local, or parent attributes.
〔总结〕从上文可得

ref属性在哪用,有什么用

略提bean作用域、bean验证对bean对象的影响。

示例代码



    


    class="org.springframework.aop.framework.ProxyFactoryBean">
    
         
    
    
2.3 Inner beans

    
    
         
            
            
        
    

〔总结〕inner bean类似于Java的内部类

2.4 Collections

Collection merging

Limitations of collection merging

Strongly-typed collection

Spring Collections 映射 Java Collections
—— List
—— Set
—— Map
—— Properties

示例代码


    
    
        
            administrator@example.org
            support@example.org
            development@example.org
        
    
    
    
        
            a list element followed by a reference
            
        
    
    
    
        
            
            
        
    
    
    
        
            just some string
            
        
    

〔总结〕根据示例代码,得以下结论:
keyvalue;value也可以是用以下属性作为key或value值:

bean | ref | idref | list | set | map | props | value | null
2.5 Null and empty string values

示例代码:2种方式为字符串设置NULL或空值

设空值时, 第1种方式:


    

设空值时, 第2种方式:

exampleBean.setEmail("")

设NULL时, 第1种方式:


    
        
    

设NULL时, 第2种方式:

exampleBean.setEmail(null)
2.6 XML shortcut with the p-namespace

代码片段


    
    
    
        
    
    
    
    

代码片段 :使用p:spouse-ref=""



    
        
        
    

    

    
        
    
2.7 XML shortcut with the c-namespace

代码片段



    
    

    
    
        
        
        
    

    
    

2.8 Compound property names

代码片段:确保fred,bob属性的值不为空,即确保不抛 NullPointerException异常


    
3. Using depends-on

depends-on的作用:
explicitly force one or more beans to be initialized before the bean using this element is initialized.

使用depends-on的场景:

a static initializer in a class needs to be triggered.

database driver registration

代码片段 1


代码片段 2


    



〔总结〕参阅现有博客提供的博主,及具体应用场景

4. Lazy-initialized beans

延迟加载(初始化)bean对象。

By default, ApplicationContext implementations eagerly create and configure all singleton beans as part of the initialization process. Generally, this pre-instantiation is desirable, because errors in the configuration or surrounding environment are discovered immediately, as opposed to hours or even days later. When this behavior is not desirable, you can prevent pre-instantiation of a singleton bean by marking the bean definition as lazy-initialized. A lazy-initialized bean tells the IoC container to create a bean instance when it is first requested, rather than at startup.

代码示例


When the preceding configuration is consumed by an ApplicationContext, the bean named lazy is not eagerly pre-instantiated when the ApplicationContext is starting up, whereas the not.lazy bean is eagerly pre-instantiated.

However, when a lazy-initialized bean is a dependency of a singleton bean that is not lazy-initialized, the ApplicationContext creates the lazy-initialized bean at startup, because it must satisfy the singleton’s dependencies. The lazy-initialized bean is injected into a singleton bean elsewhere that is not lazy-initialized.

代码示例: 控制懒加载级别


    

〔总结〕参阅《官档》,多次阅读原文旨意。

5. Autowiring collaborators

自动装配的优势?

自动装配的劣势?

自动装配的模式?

自动装配的限制?

自动装配的应用?

〔总结〕Spring有能力自动装配协作者(即对象之间存在依赖关系)。
自动装配的优点:

Autowiring can significantly reduce the need to specify properties or constructor arguments.

Autowiring can update a configuration as your objects evolve. For example, if you need to add a dependency to a class, that dependency can be satisfied automatically without you needing to modify the configuration.

〔理论总结〕使用自动装配后,配置文件具备自更新能力。主流开发的趋势之一。

autowire //基于XML
5.1 Limitations and disadvantages of autowiring

Explicit dependencies in property and constructor-arg settings always override autowiring. You cannot autowire so-called simple properties such as primitives, Strings, and Classes (and arrays of such simple properties). This limitation is by-design.

Autowiring is less exact than explicit wiring. Although, as noted in the above table, Spring is careful to avoid guessing in case of ambiguity that might have unexpected results, the relationships between your Spring-managed objects are no longer documented explicitly.

Wiring information may not be available to tools that may generate documentation from a Spring container.

Multiple bean definitions within the container may match the type specified by the setter method or constructor argument to be autowired. For arrays, collections, or Maps, this is not necessarily a problem. However for dependencies that expect a single value, this ambiguity is not arbitrarily resolved. If no unique bean definition is available, an exception is thrown.

5.2 Excluding a bean from autowiring

禁用某特定bean的自动装配功能

用法

作用

5.2.1 用法

基于XML

autowire-candidate=false 

基于注解

@Autowired
5.2.2 作用

unavailable to the autowiring infrastructure.
only affect type-based autowiring.

6. Method injection

主要用于解决以下场景:
在大多数应用场景中,bean对象一般都是单例对象。但在bean对象的依赖情况下:

一个单例依赖另一个单例

一个非单例依赖另一个非单例

古老的做法:是将一个bean定义为另一个bean的属性。以此建立依赖关系。

如:A-bean 依赖 B-bean,那么POJO可定义为:

public class A{
    public B b;
}

public class B{}

bean之间的依赖关系建立后,会产生一个问题: 两个bean的生命周期不一样,怎么办?
古老的做法是这样子的,见代码示例:
【代码示例说明】:

CommandManager obejct在系统架构中属于业务逻辑层(SERVICE)

CommadManger object的开放式方法process(Map commandState)的调用依赖Command obejct

根据【1.】和【2.】可得,两个类之间存在密切的依赖关系。所以Spring提供一种方式:当依赖方(CommandManager)的行为受制于被依赖方(Command)时,可以在依赖方内部实现被依赖方的初始化。完成上述行为的前提的是:依赖方(CommandManager)需要实现接口ApplicationContextAware

// a class that uses a stateful Command-style class to perform some processing
package fiona.apple;

// Spring-API imports
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

//依赖方(CommanderManager)现了ApplicationContextAware
public class CommandManager implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    //process()的执行受制于Command对象
    public Object process(Map commandState) {
        
        Command command = createCommand();
       
        command.setState(commandState);
        
        return command.execute();
    }

    protected Command createCommand() {
        // notice the Spring API dependency!
        return this.applicationContext.getBean("command", Command.class);
    }

    public void setApplicationContext(
            ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

这种做法需要你放弃Spring framework的IoC特性。以上述代码来看,bean object有两个:CommandManagerCommand。需要分析以下几个问题

两个bean object中,依赖方是谁? 被依赖方又是谁?
answer:依赖方:CommandManager; 被依赖方:Command

被依赖方的bean obejct的生命周期如何得到保证?
answer:要保证被依赖方的生命周期随时不死。那么依赖方实现接口ApplicationContextAware,目的是为了调用Spring framework的方法

这种在业务层耦合Spring framework代码已破化IoC原则,因为在实现接口的那一刻起,IoC原则就已经被破坏了。即这种解决方案不可取。Spring给出了2种可靠的方案:

lookup method injection

arbitrary method replacement

〔经验之道〕业务层的所有代码应该满足以下注释要求

// no more Spring imports!
6.1 Lookup method injection

参阅《官档》,思考代码示例逻辑

6.2 Arbitrary method replacement

参阅《官档》,思考代码示例逻辑

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70372.html

相关文章

  • Broadleaf概念

    摘要:本部分是可以找到有关功能和概念的大部分信息的地方。促销系统包含一个高度可配置的促销系统。异步消息通过与现代代理交互,实现应用程序消息的异步处理。将智能地将自己的配置信息与实施者在运行时提供的信息合并。添加了方法以允许包含任何符合的加密方案。 本部分是可以找到有关Broadleaf功能和概念的大部分信息的地方。我们描述了购物车修改,定价和付款等操作的重要性,以及Broadleaf支持的其...

    peixn 评论0 收藏0
  • Spring Boot 2.1.2 & Spring Cloud Greenwich 升级

    摘要:节前没有新业务代码,正好刚发布,于是开始为期四天的框架代码升级。还好并没有使用它的,配置上有一个小坑,的是表示而是表示,之前配置成的,如果到的里面那就要抛异常了。 节前没有新业务代码,正好Greenwich刚发布,于是开始为期四天的框架代码升级。 之前的版本是 spring boot 1.5.10 , spring cloud Edgware.SR3 依赖升级 增加依赖管理插件 ap...

    newsning 评论0 收藏0
  • Spring Boot Reference Guide Memorandum

    此文章为Spring Boot Reference Guide(2.1.5.RELEASE)的备忘录。 Chapter 8. Introducing Spring Boot You can use Spring Boot to create a Java application that can be started by using java -jar or more traditional w...

    imccl 评论0 收藏0
  • 厉害了,Spring Cloud for Alibaba 来了!

    摘要:栈长有话说其实项目就是为了阿里的项目能很好的结合融入使用,这个项目目前由阿里维护。对同时使用和阿里巴巴项目的人来说无疑带来了巨大的便利,一方面能结合无缝接入,另一方面还能使用阿里巴巴的组件,也带来了更多的可选择性。 最近,Spring Cloud 发布了 Spring Cloud Alibaba 首个预览版本:Spring Cloud for Alibaba 0.2.0. 大家都好奇,...

    lbool 评论0 收藏0

发表评论

0条评论

MonoLog

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<