ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

分析 Spring 框架中的装配模式

2021-05-30 14:52:12  阅读:256  来源: 互联网

标签:装配 框架 Spring springframework helloWorld beans HelloWorld org public


 

Spring框架中,对于不同的bean进行组合实现复杂功能的过程称为装配。

1、装配模式介绍

在Spring中,支持5种装配模式:

  • no – 缺省情况下,自动配置是通过“ref”属性手动设定。

  • byType – 按数据类型自动装配。如果一个bean的数据类型是用其它bean属性的数据类型,兼容并自动装配它。

  • byName – 根据属性名称自动装配。如果一个bean的名称和其他bean属性的名称是一样的,将会自装配它。

  • constructor – 在构造函数参数的byType方式。

  • autodetect – 如果找到默认的构造函数,使用“自动装配用构造”; 否则,使用“按类型自动装配”。

接下来,我们通过如下的代码对这几种装配模式做下简单测试。代码结构如下:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

structure of the project

代码如下:

pom.xml:

    4.0.0    com.SpaceCat.SpringHelloWorld    SpringHelloWorld    1.0-SNAPSHOT            
        
                    org.springframework            spring-core            4.1.4.RELEASE                
        
                    org.springframework            spring-context            4.1.4.RELEASE            // Interface HelloWorld
public interface HelloWorld {
    public void sayHello();
}
 

.

// Class implements HelloWorld
public class SpringHelloWorld implements HelloWorld {
   public void sayHello()  {
           System.out.println("Spring say Hello!");
   }
}

// Other class implements HelloWorld
public class StrutsHelloWorld implements HelloWorld {
   public void sayHello()  {
           System.out.println("Struts say Hello!");
   }
}

public class HelloWorldService {
    private HelloWorld helloWorld;

    public HelloWorldService() {

    }

    public HelloWorldService(HelloWorld h) {
        this.helloWorld = h;
    }

    public void setHelloWorld(HelloWorld helloWorld) {
        this.helloWorld = helloWorld;
    }

    public HelloWorld getHelloWorld() {
        return this.helloWorld;
    }
}
 

HelloWorldProgram.java:

package com.SpaceCat.HelloWorld.spring;

import com.SpaceCat.HelloWorld.spring.helloworld.HelloWorld;
import com.SpaceCat.HelloWorld.spring.helloworld.HelloWorldService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by chengxia on 2019/4/30.
 */
public class HelloWorldProgram {
    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        HelloWorldService service = (HelloWorldService) context.getBean("helloWorldService");
        HelloWorld hw= service.getHelloWorld();
        hw.sayHello();
    }
}
 

在下面的例子中,我们通过修改beans.xml配置文集爱你,然后,运行HelloWorldProgram.java就可以对这几种装配模式进行举例说明。

1.1 no

缺省情况下,可以通过“ref”属性手动设定bean之间的关联关系。

                                
 

运行结果:

Spring Say Hello!!

Process finished with exit code 0
 

1.2 byType

按数据类型自动装配。如果一个bean的数据类型是用其它bean属性的数据类型,兼容并自动装配它。

接下来的例子中,我们只定义一个HelloWord类型的bean,然后,在定义bean时,通过autowire属性设置自动装配类型为byType。即可完成bean装配。

                
 

运行结果:

Struts Say Hello!!

Process finished with exit code 0
 

1.3 byName

根据属性名称自动装配。如果一个bean的名称和其他bean属性的名称是一样的,将会自装配它。

接下来,我们将一个bean的id设置为与HelloWorldService类的属性名(helloWorld)一致。这样,这个bean就会自动被装配到HelloWorldService。

                
 

运行结果:

Spring Say Hello!!

Process finished with exit code 0
 

1.4 constructor

在构造函数参数的byType方式。就是根据构造函数参数的类型进行自动装配,如果有一个bean的类型和HelloWorldService类的构造函数类型一样,就会被自动装配过去。

                
 

运行结果:

Struts Say Hello!!

Process finished with exit code 0
 

1.5 autodetect

这种有些资料写的有些歧义,下面是Stack Overflow上面的一个解释:

Autowiring by autodetect uses either of two modes i.e. constructor or byType modes. First it will try to look for valid constructor with arguments, If found the constructor mode is chosen. If there is no constructor defined in bean, or explicit default no-args constructor is present, the autowire byType mode is chosen.

意思就是:如果发现带参数的构造函数,就使用constructor模式进行装配;如果没有定义构造函数,或者是显式定义了没有参数的构造函数,就使用byType模式进行装配。

这里我测试用的环境中,spring的版本是4.1.4.RELEASE,在测试时IDEA提示报错,如下图:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

autodetect error tips

可能在高版本的Spring框架中这种装配模式已经不推荐使用了。但是,运行时仍然可以正常运行,如下:

                
 

运行结果:

Struts Say Hello!!

Process finished with exit code 0
 

2、更加细粒度的装配控制

2.1 特定属性的自动装配

在前面装配模式介绍的例子中,如果一个bean配置了autowire属性,那么它的所有属性都会被自动装配。但是,有时候,我们只希望某些特定的属性配装配。这时候,就需要用到@Autowired注解。

在Spring框架中,可以使用@Autowired注解通过setter方法,构造函数或字段自动装配Bean。通过它,可以对某个特定的bean属性完成自动装配。@Autowired注解是通过匹配数据类型自动装配Bean的。

启用@Autowired需要注册“AutowiredAnnotationBeanPostProcessor',可以通过两种方式:

在beans.xml文件中,加入(包括xmlns:context="http://www.springframework.org/schema/context")

                    
 

在beans.xml中添加

                    
 

这样,我们就可以通过将@Autowired注解用到bean的特定属性、setter方法或者构造函数等,来实现对自动装配更加细粒度的控制。


下面的例子中,三种实现的效果一样:

1. 用在属性上

package com.SpaceCat.HelloWorld.spring.helloworld;

import org.springframework.beans.factory.annotation.Autowired;

/**
 * Created by chengxia on 2019/4/30.
 */
public class HelloWorldService {
    @Autowired
    private HelloWorld helloWorld;

    public HelloWorldService() {

    }

    public HelloWorldService(HelloWorld h) {
        this.helloWorld = h;
    }

    public void setHelloWorld(HelloWorld helloWorld) {
        this.helloWorld = helloWorld;
    }

    public HelloWorld getHelloWorld() {
        return this.helloWorld;
    }
}
 

2. 用在构造函数上

package com.SpaceCat.HelloWorld.spring.helloworld;

import org.springframework.beans.factory.annotation.Autowired;

/**
 * Created by chengxia on 2019/4/30.
 */
public class HelloWorldService {
    private HelloWorld helloWorld;

    public HelloWorldService() {

    }

    @Autowired
    public HelloWorldService(HelloWorld h) {
        this.helloWorld = h;
    }

    public void setHelloWorld(HelloWorld helloWorld) {
        this.helloWorld = helloWorld;
    }

    public HelloWorld getHelloWorld() {
        return this.helloWorld;
    }
}
 

3. 用在setter方法上

package com.SpaceCat.HelloWorld.spring.helloworld;

import org.springframework.beans.factory.annotation.Autowired;

/**
 * Created by chengxia on 2019/4/30.
 */
public class HelloWorldService {
    private HelloWorld helloWorld;

    public HelloWorldService() {

    }

    public HelloWorldService(HelloWorld h) {
        this.helloWorld = h;
    }

    @Autowired
    public void setHelloWorld(HelloWorld helloWorld) {
        this.helloWorld = helloWorld;
    }

    public HelloWorld getHelloWorld() {
        return this.helloWorld;
    }
}
 

运行结果如下:

Struts Say Hello!!

Process finished with exit code 0
 

这里需要注意的是,这个注解并不是只通过byType的方式进行自动装配。准确地说:

@Autowired注入首先根据byType注入,当类型大于1时在根据byName注入。

2.2 指定自动装配特定的bean

在上面介绍的装配模式中,如果有两个符合条件的bean,框架就会报错,如下:

package com.SpaceCat.HelloWorld.spring.helloworld;

import org.springframework.beans.factory.annotation.Autowired;

/**
 * Created by chengxia on 2019/4/30.
 */
public class HelloWorldService {
    private HelloWorld helloWorld;

    public HelloWorldService() {

    }

    public HelloWorldService(HelloWorld h) {
        this.helloWorld = h;
    }

    @Autowired
    public void setHelloWorld(HelloWorld helloWorld) {
        this.helloWorld = helloWorld;
    }

    public HelloWorld getHelloWorld() {
        return this.helloWorld;
    }
}
 

.

                            
 

运行如下:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'helloWorldService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.SpaceCat.HelloWorld.spring.helloworld.HelloWorldService.setHelloWorld(com.SpaceCat.HelloWorld.spring.helloworld.HelloWorld); nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.SpaceCat.HelloWorld.spring.helloworld.HelloWorld] is defined: expected single matching bean but found 2: strutsHelloWorld,springHelloWorld
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1202)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:762)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
    at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:139)
    at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:83)
    at com.SpaceCat.HelloWorld.spring.HelloWorldProgram.main(HelloWorldProgram.java:14)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.SpaceCat.HelloWorld.spring.helloworld.HelloWorldService.setHelloWorld(com.SpaceCat.HelloWorld.spring.helloworld.HelloWorld); nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.SpaceCat.HelloWorld.spring.helloworld.HelloWorld] is defined: expected single matching bean but found 2: strutsHelloWorld,springHelloWorld
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:649)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
    ... 13 more
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.SpaceCat.HelloWorld.spring.helloworld.HelloWorld] is defined: expected single matching bean but found 2: strutsHelloWorld,springHelloWorld
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1061)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:949)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:606)
    ... 15 moreProcess finished with exit code 1
 

这时候,可以通过@Quanlifier告诉Spring哪些bean应当自动装配。如下:

package com.SpaceCat.HelloWorld.spring.helloworld;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

/**
 * Created by chengxia on 2019/4/30.
 */
public class HelloWorldService {

    @Autowired
    @Qualifier(value = "strutsHelloWorld")
    private HelloWorld helloWorld;

    public HelloWorldService() {

    }

    public HelloWorldService(HelloWorld h) {
        this.helloWorld = h;
    }

    public void setHelloWorld(HelloWorld helloWorld) {
        this.helloWorld = helloWorld;
    }

    public HelloWorld getHelloWorld() {
        return this.helloWorld;
    }
}
 

注意,这里其实要同时修改beans.xml文件,否则,@Qualifier注解不起作用(应该主要是为了添加)。如下:

                            
 

运行结果:

Struts Say Hello!!

Process finished with exit code 0
 


标签:装配,框架,Spring,springframework,helloWorld,beans,HelloWorld,org,public
来源: https://blog.51cto.com/u_15233911/2833563

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有