• Spring bean依赖注入、bean的装配及相关注解


    依赖注入

    Spring主要提供以下两种方法用于依赖注入

    • 基于属性Setter方法注入
    • 基于构造方法注入

    Setter方法注入

    例子:

    public class Communication {
     
        private Messaging messaging;
          
         /*
         * DI via Setter
         */
        public void setMessaging(Messaging messaging){
            this.messaging = messaging;
        }
     
        public void communicate(){
            messaging.sendMessage();
        }
    }

    如上Communication类有一个messaging属性,并含有setMessaging方法,那么使用Setter方法注入的时候,只需要使用如下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" xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
     
        <bean id="activeMqMessaging" class="com.websystique.spring.domain.impl.ActiveMQMessaging" />
     
        <bean id="communication" class="com.websystique.spring.Communication">
            <property name="messaging">
                <ref bean="activeMqMessaging" />
            </property>
        </bean>
     
    </beans>

    这里省略了ActiveMQMessaging的定义,实际上ActiveMQMessaging类是Messaging接口的一个实现类。

    构造方法注入

    例子

    public class Communication {
     
        private Encryption encryption;
         
        /*
         * DI via Constructor Injection
         */
        public Communication(Encryption encryption){
            this.encryption = encryption;
        }
     
     
        public void communicate(){
            encryption.encryptData();
        }
     
    }

    注意以上Communication类有一个构造方法Communication(Encryption encryption),且含有一个入参,类型为Encryption,那么使用构造方法注入的时候,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" xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
     
        <bean id="rsaEncryption" class="com.websystique.spring.domain.impl.RSAEncryption" />
     
        <bean id="communication" class="com.websystique.spring.Communication">
            <constructor-arg type="com.websystique.spring.domain.Encryption">
                <ref bean="rsaEncryption" />
            </constructor-arg>
        </bean>
     
    </beans>

    注意,这里省略了RSAEncryption的定义,不用在意这些细节,该类是Encryption接口的一个实现类。

    另外,为了避免构造方法重载带来的歧义,这里指定了入参类型为com.websystique.spring.domain.Encryption。

    装配

    bean的装配有两种方式,手动装配和自动装配。注意,不要混淆,bean的装配是依赖注入的具体行为,依赖注入的时候需要根据bean的名称或类型等进行装配。

    手动装配:通过在<property> 或者 <constructor>标签中使用ref属性,在上一小节的“依赖注入”部分使用的就是手动装配;

    <!-- default example (autowire="no") -->
    <bean id="driver" class="com.websystique.spring.domain.Driver">
        <property name="license" ref="license"/>
    </bean>
     
    <bean id="license" class="com.websystique.spring.domain.License" >
        <property name="number" value="123456ABCD"/>
    </bean>

    自动装配:在<bean>标签中使用autowire属性;

    <bean id="application" class="com.websystique.spring.domain.Application" autowire="byName"/>

    本小节主要关注自动装配,自动装配有以下四种方式:

    • autowire="byName" : 根据名称
    • autowire="byType" : 根据类型
    • autowire="constructor" : 根据构造方法入参类型
    • autowire="no" : 不使用自动装配,即默认方式,手动装配

    autowire="byName"

    例子:

    public class Application {
     
        private ApplicationUser applicationUser;
     
        public ApplicationUser getApplicationUser() {
            return applicationUser;
        }
     
        public void setApplicationUser(ApplicationUser applicationUser) {
            this.applicationUser = applicationUser;
        }
     
        @Override
        public String toString() {
            return "Application [applicationUser=" + applicationUser + "]";
        }
    }

    该类有一个属性叫applicationUser,那么根据名称自动装配的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" xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
     
        <!-- byName example -->
        <bean id="application" class="com.websystique.spring.domain.Application" autowire="byName"/>
     
        <bean id="applicationUser" class="com.websystique.spring.domain.ApplicationUser" >
            <property name="name" value="superUser"/>
        </bean>
    </beans>

    autowire="byType"

    例子

    public class Employee {
     
        private EmployeeAddress address;
     
        public EmployeeAddress getAddress() {
            return address;
        }
     
        public void setAddress(EmployeeAddress address) {
            this.address = address;
        }
     
        @Override
        public String toString() {
            return "Employee [address=" + address + "]";
        }
    }

    该类有一个属性类型为EmployeeAddress,那么根据类型自动装配的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" xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
     
        <!-- byType example -->
        <bean id="employee" class="com.websystique.spring.domain.Employee" autowire="byType"/>
     
        <bean id="employeeAddress" class="com.websystique.spring.domain.EmployeeAddress" >
            <property name="street" value="112/223,SantaVila"/>
            <property name="city" value="Nebraska"/>
        </bean>
     
    </beans>

    autowire="constructor"

    例子

    public class Performer {
         
        private Instrument instrument;
         
        public Performer(Instrument instrument){
            this.instrument = instrument;
        }
     
        @Override
        public String toString() {
            return "Performer [instrument=" + instrument + "]";
        }
    }

    该类有一个构造方法,入参的类型为Instrument,那么根据构造方法自动装配的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" xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
     
        <!-- constructor example -->
        <bean id="performer" class="com.websystique.spring.domain.Performer" autowire="constructor"/>
     
        <bean id="instrument" class="com.websystique.spring.domain.Instrument" >
            <property name="name" value="PIANO"/>
        </bean>
     
    </beans>

    autowire="no"

    public class Driver {
     
        private License license;
         
        public void setLicense(License license) {
            this.license = license;
        }
     
        public License getLicense() {
            return license;
        }
     
        @Override
        public String toString() {
            return "Driver [license=" + license + "]";
        }
    }

    该类有一个属性license,由于我们不打算使用自动装配功能,那么只能使用手动装配了,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" xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
     
        <!-- default example (autowire="no") -->
        <bean id="driver" class="com.websystique.spring.domain.Driver" autowire="no">
            <property name="license" ref="license"/>
        </bean>
     
        <bean id="license" class="com.websystique.spring.domain.License" >
            <property name="number" value="123456ABCD"/>
        </bean>
     
    </beans>

    注意,如果不配置license的ref引用的话,license将为null。

    相关注解

    主要涉及以下三个注解

    • @Autowired
    • @Resource
    • @Qualifier

    @Autowired可应用于构造方法、属性、setter方法或配置类@Configuration的方法上,该注解根据bean的数据类型进行装配,如果你想希望根据bean的名称进行装配可以使用带name属性的@Resource注解;另外@Qualifier注解经常与@Autowired注解结合使用,用于解决一个应用中存在多个同种类型的bean的情况,下面将给出各个注解的示例。

    @Autowired(根据类型自动装配)

    setter方法上

    @Component("driver")
    public class Driver {
     
        private License license;
         
        @Autowired
        public void setLicense(License license) {
            this.license = license;
        }
     
        @Override
        public String toString() {
            return "Driver [license=" + license + "]";
        }
        //getter
    }

    构造方法上

    @Component("driver")
    public class Driver {
     
        private License license;
         
        @Autowired
        public Driver(License license){
            this.license = license;
        }
         
        @Override
        public String toString() {
            return "Driver [license=" + license + "]";
        }
    }

    属性上

    @Component("driver")
    public class Driver {
        @Autowired
        private License license;
         
        //getter,setter
     
        @Override
        public String toString() {
            return "Driver [license=" + license + "]";
        }
    }

    @Resource(根据名称装配)

    @Component("application")
    public class Application {
     
        @Resource(name="applicationUser")
        private ApplicationUser user;
     
        @Override
        public String toString() {
            return "Application [user=" + user + "]";
        }
    }

    @Qualifier(与@Autowired结合使用,实现按名称装配)

    例子背景::存在两个Car接口的实现类,其中一个Car接口的实现类已被注册为bean,且name为Mustang

    @Component
    public class Bond {
     
        @Autowired
        @Qualifier("Mustang")
        private Car car;
         
        public void showCar(){
            car.getCarName();
        }
    }

    注意,以上例子如果不使用@Qualifier限定的话,将抛出如下异常,表明存在多个类型相同的bean:

    Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.websystique.spring.domain.Car] is defined: expected single matching bean but found 2: Ferari,Mustang
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:970)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858)
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480)
        ... 14 more

    最后提醒下,被@Autowired注解标注默认情况下能保证成功注入,如果注入不成功(往往是找不到,或存在歧义),Spring会抛出异常。当然,有时候可能会有特殊需求,不希望bean被强制装配,那么可以在@Autowired上添加required=false属性,表明该bean的装配是可选的,找不到的话,就为null吧,如下示例:

    @Component("driver")
    public class Driver {
        @Autowired(required=false)
        private License license;
         
        //getter,setter
     
        @Override
        public String toString() {
            return "Driver [license=" + license + "]";
        }
    }

    基于以上原因,虽然@Autowired注解与@Resource功能类似,但是@Autowired还是比@Resource强大了那么一点点,个人建议使用@Autowired注解。

    参考资料

    http://websystique.com/spring/spring-dependency-injection-example-with-constructor-and-property-setter-xml-example/

    http://websystique.com/spring/spring-beans-auto-wiring-example-using-xml-configuration/

    http://websystique.com/spring/spring-dependency-injection-annotation-beans-auto-wiring-using-autowired-qualifier-resource-annotations-configuration/

     
  • 相关阅读:
    maven项目部署到tomcat中没有classe文件的问题汇总
    Tomcat远程调试模式及利用Eclipse远程链接调试
    FastDFS 常见问题
    Linux Crontab 定时任务 命令详解
    EChart 关于图标控件的简单实用
    java 通过zxing生成二维码
    Mybatis typeAliases别名
    Mybatis 实现手机管理系统的持久化数据访问层
    Mybatis 实现传入参数是表名
    Mybatis关于like的字符串模糊处理
  • 原文地址:https://www.cnblogs.com/chenpi/p/6222595.html
Copyright © 2020-2023  润新知