欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring提供的三种装配Bean方式

程序员文章站 2023-01-01 09:44:22
Spring提供了三种主要的装配Bean的方式:隐式的bean发现和自动化装配,在Java中进行显示配置,在XML中进行显示配置。 ......

在spring中,对象不需要自己查找或创建与其所关联的其他对象,spring容器负责把需要相互协作的对象引用赋予各个对象。创建应用对象之间协作关系的行为通常称为装配(wiring),这也是依赖注入(di)的本质。

spring提供了三种主要的装配bean的方式:

  • 隐式的bean发现和自动化装配
  • 在java中进行显示配置
  • 在xml中进行显示配置

 

隐式的bean发现和自动化装配

 

 spring从两个方面来实现自动化装配:

  • 组件扫描:spring会自动发现应用上下文中所创建的bean。
  • 自动装配:spring自动满足bean之间的依赖。

示例代码:

package phone;

public interface hwphone {
    void call();
}

 

package phone;

import org.springframework.beans.factory.annotation.qualifier;
import org.springframework.stereotype.component;

@component("p30phone")
@qualifier("p30")
public class p30phone implements hwphone {
    @override
    public void call() {
        system.out.println("使用 p30 手机呼叫...");
    }
}

@component注解表明该类会作为组件类,spring会为这个类创建bean。“p30phone"是定义bean的id。

@qualifier("p30")创建自定义限定符,防止不仅有一个bean能够匹配结果。

 

package phone;

import org.springframework.beans.factory.annotation.qualifier;
import org.springframework.stereotype.component;

@component("mete30phone")
@qualifier("mete30")
public class mete30phone implements hwphone {
    @override
    public void call() {
        system.out.println("使用 mete30 手机呼叫...");
    }
}

 

package phone;

import org.springframework.beans.factory.annotation.autowired;
import org.springframework.beans.factory.annotation.qualifier;
import org.springframework.stereotype.component;

@component("lihua")
public class somebody {

    @autowired
    @qualifier("p30")
    private hwphone hwphone;

    public void usephone() {
        hwphone.call();
    }
}
@autowired 自动装配。
@qualifier("p30")使用限定符。

 

package phone;

import org.springframework.context.annotation.componentscan;
import org.springframework.context.annotation.configuration;

@configuration
@componentscan(basepackages = {"phone"})
public class phoneconfig {
}
@componentscan启动注解扫描,basepackages={"phone"},指定扫描phone包和phone下的子包;不配置basephckages则扫描当前配置类的包和子包。

 

package phone;

import org.springframework.context.annotation.annotationconfigapplicationcontext;

public class main {
    public static void main(string[] args) {
        annotationconfigapplicationcontext context = new annotationconfigapplicationcontext(phoneconfig.class);
        somebody somebody = (somebody) context.getbean("lihua");
        somebody.usephone();
    }
}

运行结果:

使用 p30 手机呼叫...

 

在java中进行显示配置

 想要将第三方库中的组件装配到你的应用中,是没有办法在它的类上添加@component和@autowired注解的,这时就不能使用自动化装配了,必须采用显式配置,而显示配置有两种可选方式:使用java配置或xml配置。javaconfig是配置代码,它不应包含任何业务逻辑,也不应侵入到业务逻辑代码之中。

在上一节的示例代码中,改为如下代码:

package phone;

public interface hwphone {
    void call();
}

 

package phone;

public class p30phone implements hwphone {
    @override
    public void call() {
        system.out.println("使用 p30 手机呼叫...");
    }
}

 

package phone;

public class mete30phone implements hwphone {
    @override
    public void call() {
        system.out.println("使用 mete30 手机呼叫...");
    }
}

此处删除了@component注解,和 @qualifier注解。

package phone;

public class somebody {
    private hwphone hwphone;
    
    public somebody(hwphone hwphone) {
        this.hwphone = hwphone;
    }

    public void usephone() {
        hwphone.call();
    }
}

删除了@autowired注解,以构造器传入hwphone引用对象,也可以通过set方法设置引用对象。

package phone;

import org.springframework.beans.factory.annotation.qualifier;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;

@configuration
public class phoneconfig {
    @bean
    @qualifier("p30")
    public p30phone p30phone() {
        return new p30phone();
    }
    
    @bean
    @qualifier("mete30")
    public mete30phone mete30phone() {
        return new mete30phone();
    }
    
    @bean(name = "lihua")
    public somebody somebody() {
        return new somebody(mete30phone());
    }
    
    @bean(name = "xiaoming")
    public somebody someone(@qualifier("p30") hwphone phone) {
        return new somebody(phone);
    }
}

此处删除了@componentscan注解,以javaconfig方式配置bean。

“lihua”这个bean是通过调用mete30phone()得到的,但情况并非完全如此。因为mete30phone()方法上添加了@bean注解,spring将会拦截所有对它的调用,并确保直接返回该方法所创建的bean,而不是每次都对其进行实际的调用。

“xiaoming”这个bean,someone() 方法请求一个hwphone作为参数。当spring调用someone()创建bean时,它会自动装配一个hwphone到配置方法之中。此处的@qualifier("p30")作为限定符,防止两个bean(p30phone和mete30phone)都能够匹配结果。

package phone;

import org.springframework.context.annotation.annotationconfigapplicationcontext;

public class main {
    public static void main(string[] args) {
        annotationconfigapplicationcontext context = new annotationconfigapplicationcontext(phoneconfig.class);
        somebody somebody = (somebody) context.getbean("lihua");
        somebody.usephone();
        somebody someone = (somebody) context.getbean("xiaoming");
        someone.usephone();
    }
}

运行结果:

使用 mete30 手机呼叫...
使用 p30 手机呼叫...

 

在xml中进行显示配置

 在javaconfig中所需要的只是@configuration,但在使用xml时,需要在配置文件的顶部声明多个xml模式(xsd)文件,这些文件定义了配置spring的xml元素。

创建一个application.xml配置文件:

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
       xsi:schemalocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
       <bean id="p30phone" class="phone.p30phone"/>
       <bean id="mete30phone" class="phone.mete30phone"/>
       <bean id="lihua" class="phone.somebody">
           <constructor-arg ref="p30phone"/>
       </bean>
       <bean id="xiaoming" class="phone.somebody">
           <constructor-arg ref="mete30phone"/>
       </bean>
</beans>

基于上一节的示例,不用phoneconfig配置类,并使用classpathxmlapplicationcontext创建spring容器,main方法如下:

package phone;

import org.springframework.context.support.classpathxmlapplicationcontext;

public class main {
    public static void main(string[] args) {
        classpathxmlapplicationcontext context = new classpathxmlapplicationcontext("phone/application.xml");
        somebody somebody = (somebody) context.getbean("lihua");
        somebody.usephone();
        somebody someone = (somebody) context.getbean("xiaoming");
        someone.usephone();
    }
}

运行结果:

使用 p30 手机呼叫...
使用 mete30 手机呼叫...

 

导入和混合配置

在javaconfig中引用xml

package phone;

import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;

@configuration
public class phoneconfig {
    @bean
    public p30phone p30phone() {
        return new p30phone();
    }
    
    @bean
    public mete30phone mete30phone() {
        return new mete30phone();
    }
}

此处只配置phone的两个bean。

 

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
       xsi:schemalocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">

       <bean id="lihua" class="phone.somebody">
           <constructor-arg ref="p30phone"/>
       </bean>
       <bean id="xiaoming" class="phone.somebody">
           <constructor-arg ref="mete30phone"/>
       </bean>
</beans>

xml配置文件配置了"lihua"和"xiaoming"两个somebody的bean。

 

package phone;

import org.springframework.context.annotation.configuration;
import org.springframework.context.annotation.import;
import org.springframework.context.annotation.importresource;

@configuration
@import({phoneconfig.class})
@importresource("classpath:phone/application.xml")
public class somebodyconfig {

}

配置通过@import引用phone的配置,以及通过@importresource引用xml的配置

 

package phone;

import org.springframework.context.annotation.annotationconfigapplicationcontext;

public class main {
    public static void main(string[] args) {
        annotationconfigapplicationcontext context = new annotationconfigapplicationcontext(somebodyconfig.class);
        somebody somebody = (somebody) context.getbean("lihua");
        somebody.usephone();
        somebody someone = (somebody) context.getbean("xiaoming");
        someone.usephone();
    }
}

运行结果:

使用 p30 手机呼叫...
使用 mete30 手机呼叫...

 

参考《spring实战(第4版)》