(7)依赖

由于这篇文档涉及的知识点有点多,于是在此写个目录:

1.依赖注入
2.依赖关系和配置详细
3.使用依赖
4.懒加载bean
5.自动装配
6.方法注入

1.依赖注入

依赖注入(DI)是一个过程,通过这个过程,对象定义它们的依赖关系,即它们使用的其他对象,在spring中这个过程基本上是反向的,因此名称Inversion of Control(IoC),由spring统一管理bean的生命周期和行为。

依赖注入主要存在两种方式注入:

  • 基于构造函数的依赖注入
       构造函数参数类型匹配
       构造函数参数索引匹配
       构造函数参数名称匹配
  • 基于Setter的依赖注入

例子演示,由于例子比较简单,直接上代码,注意理解是如何注入的
邮件email类

/**
 * @Project: spring
 * @description:  email 引用类型
 * @author: sunkang
 * @create: 2018-09-11 21:49
 * @ModificationHistory who      when       What
 **/
public class Email {

    private String temail ;

    public Email() {
    }

    public String getEmail() {
        return temail;
    }

    public void setEmail(String email) {
        this.temail = email;
    }

    @Override
    public String toString() {
        return "Email{" +
                "email='" + temail + '\'' +
                '}';
    }
}

person类

/**
 * @Project: spring
 * @description:  演示注入的person类
 * @author: sunkang
 * @create: 2018-09-11 21:49
 * @ModificationHistory who      when       What
 **/
public class Person {

    private String  username;

    private int age;

    private Email email;

    public Person(String username, int age, Email email) {
        this.username = username;
        this.age = age;
        this.email = email;
    }

    public Person() {
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Email getEmail() {
        return email;
    }

    public void setEmail(Email email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "Person{" +
                "username='" + username + '\'' +
                ", age=" + age +
                ", email=" + email +
                '}';
    }
}

在spring-dependency.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.xsd">
    
    <bean id="emial" class="com.spring.beanDependency.inject.Email">
        <property name="email" value="2450582221@qq.com"/>
    </bean>
    <!--对于有参数的构造注入  有以下三种方式-->
    <!--1.构造函数参数类型匹配-->
    <bean id="person1" class="com.spring.beanDependency.inject.Person">
        <constructor-arg type="java.lang.String" value="sunkang"/>
        <constructor-arg type="int" value="24"/>
        <constructor-arg type="com.spring.beanDependency.inject.Email" ref="emial"/>
    </bean>
    <!--2.构造函数参数索引匹配-->
    <bean id="person2" class="com.spring.beanDependency.inject.Person">
        <constructor-arg index="0" value="sunkang"/>
        <constructor-arg index="1" value="24"/>
        <constructor-arg index="2" ref="emial"/>
    </bean>

    <!--3.构造函数参数名称匹配-->
    <bean id="person3" class="com.spring.beanDependency.inject.Person">
        <constructor-arg name="username" value="sunkang"/>
        <constructor-arg name="age" value="24"/>
        <constructor-arg name="email" ref="emial"/>
    </bean>

    <!--混合使用试试-->
    <bean id="person4" class="com.spring.beanDependency.inject.Person">
        <constructor-arg index="0" value="sunkang"/>
        <constructor-arg type="int" value="24"/>
        <constructor-arg name="email" ref="emial"/>
    </bean>
    <!--基于Setter的依赖注入,一般来说只有无参的构造函数才使用setter方法注入,一般优先使用构造函数的形式注入-->
    <!--基于setter的 DI是在调用无参数构造函数或无参数static工厂方法来实例化bean之后,通过容器调用bean上的setter方法来完成的。-->
    <!--注意一点,setter注入是根据setter方法来进行注入的,而不是根据字段的名称来注入的-->

    <bean id="person5" class="com.spring.beanDependency.inject.Person">
        <property name="username" value="sunkang"/>
        <property name="age" value="24"/>
       <!-- <property name="email" ref="emial"/>   引用bean还可以使用下面的一种方式-->
        <property name="email">
            <ref bean="emial"/>
        </property>
    </bean>
</beans>

测试代码如下:
需要注意一点的是,通过构造参数的混合注入也是正确匹配的
setter注入是根据是否有set方法的,而不是根据类中是否有这样的属性名类决定的

/**
 * @Project: spring
 * @description:  依赖注入的测试类
 * @author: sunkang
 * @create: 2018-09-11 21:52
 * @ModificationHistory who      when       What
 **/
public class DependencyTest {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beanDependency/spring-dependency.xml");
        /*-------------基于构造函数注入-----------------------*/
        Person person1 = context.getBean("person1",Person.class);
        System.out.println("1.构造函数参数类型匹配");
        System.out.println(person1);

        Person person2 = context.getBean("person2",Person.class);
        System.out.println("2.构造函数参数索引匹配");
        System.out.println(person2);

        Person person3 = context.getBean("person3",Person.class);
        System.out.println("3.构造函数参数名称匹配");
        System.out.println(person3);

        Person person4 = context.getBean("person4",Person.class);
        System.out.println("测试构造函数混合使用的情况匹配,结果是可以进行匹配");
        System.out.println(person4);

        /*-------------基于setter方法注入-----------------------*/
        Person person5 = context.getBean("person5",Person.class);
        System.out.println("基于Setter的依赖注入");
        System.out.println(person5);
    }
}

2.依赖配置和配置详解

上面已经了解了如何去实例化一个bean,那如何给类中的属性进行注入呢,如果该属性是一个list,set,properties或者map的结构,那么spring是否提供了这样的方式来进行注入

根据bean中的属性不同类型,大概有下面的几种方式

  • 直接值(比如字符串和基本类型)
  • 引用其他bean的协作者
  • 内部bean ( xml的写法像bean中定义bean)
  • 集合(list,set,map,properties 的形式该如何注入)
  • 空值和空字符串 (也就是"",和null 在spring 该如何注入)
  • 复合属性 ( xml中的属性的写法像链式写法,比如 <property name="fred.bob.sammy" value="123" />)
  • 带有p空间的xml配置方式 (就是properties的简写方式)
  • 带有c-namespace的XML快捷方式 (对应构造参数 construct-args的简写方式)
  • 直接值
    在ConfigDetail中存在字符串类型 username 和基本类型int,还有字符串类型idref属性
    注意这里省略了字段的set方法
public class ConfigDetail {
    /**
     * 一、直接值引用的方式,比如基本类型和字符串类型
     * 比如值类型为  String,int类型
     *  <idref bean="theTargetBean"/>这里是值引用,不是bean的引用,只是一种防错方法
     */
    //字符串类型
    private String username;
    //基本类型
    private int  age;

    //对应的xml配置为<idref bean="theTargetBean"/>
   // 该idref元素只是一种防错方法,可以将容器中另一个bean 的id(字符串值 - 而不是引用)
    //跟<property name="idref" value=""/> 一样的意思
    private String  idref;
}

对应的xml配置

  <property name="username" value="sunkang"/>
        <property name="age" value="23"/>
        <property name="idref" >
            <idref bean="target"/>
        </property>

这里的<idref bean = "target"/>这里是一种防错方法,主要是为了区分<ref bean=""/>,idref 的标签说明引用是bean的id这个字符串的值(而不是引用值),<ref bean=""/>是bean的引用

  • 引用其他的bean的协作者
    主要有两种方式:

方式1:<ref bean="someBean"/>
这个试试引用bean,bean可以再一个xml文档配置中,也可以不在一个xml配置中
方式2:<ref parent="parentDetail"/>
指明父类容器的bean的名称,注意,需要父容器这个对象传入到容器中,子类配置的属性值会覆盖父类配置的,配置分别在不同的配置xml中

具体演示方式2的配置
先看父集的bean的java代码

/**
 * @Project: spring
 * @description:  模拟父亲javabean 
 * @author: sunkang
 * @create: 2018-09-12 00:15
 * @ModificationHistory who      when       What
 **/
public class ConfigDetailParent {

    private String username;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
}

再来看在spring-configDetailParent.xml的具体配置

 <bean id="parentDetail" class="com.spring.beanDependency.configDetail.ConfigDetailParent">
        <property name="username"  value="parentName"/>
    </bean>

再来看在子集ConfigDetail存在ConfigDetailParent对象的引用
在ConfigDetail存在如下的引用

 private ConfigDetailParent parent;

在spring-configDetail.xml的具体配置如下,这里parentDetail会覆盖调父级的属性配置

 <bean id="parentDetail" class="com.spring.beanDependency.configDetail.ConfigDetailParent">
        <property name="username"  value="childName"/>
   </bean>
  <bean id="configDetail" class="com.spring.beanDependency.configDetail.ConfigDetail" >

       <property name="parent">
            <ref parent="parentDetail"/>
        </property>
 </bean>

注意一点的是容器的加载有所区别 ,测试如下,子容器需要指明父容器

   ApplicationContext parent = new ClassPathXmlApplicationContext("beanDependency/spring-configDetailParent.xml");

        ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"beanDependency/spring-configDetail.xml"},parent);
 /**
         * <ref parent="parentDetail"/>测试   会子类配置的属性值会覆盖父类配置的
         */
        ConfigDetailParent  parentDetail =  context.getBean("parentDetail",ConfigDetailParent.class);
        System.out.println("父类的元素为:"+parentDetail.getUsername());
        System.out.println("子类的元素为:"+configDetail.getParent().getUsername());

测试结果如下:

父类的元素为:childName
子类的元素为:parentName
  • 内部bean
    模拟内部bean的实体
/**
 * @Project: spring
 * @description:  模拟内部bean的方式
 * @author: sunkang
 * @create: 2018-09-12 09:22
 * @ModificationHistory who      when       What
 **/
public class InsideBean {
    private String  beanName;

    private String  description;
    public String getBeanName() {
        return beanName;
    }

    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @Override
    public String toString() {
        return "InsideBean{" +
                "beanName='" + beanName + '\'' +
                ", description='" + description + '\'' +
                '}';
   }

在configDetail存在内部bean的引用

 private InsideBean insideBean;

在xml的配置,就是属性嵌套了一个bean

 <property name="insideBean"  >
            <bean  class="com.spring.beanDependency.configDetail.InsideBean">
                <property name="beanName" value="内部bean"/>
                <property name="description" value="我是一个内部bean"/>
            </bean>
   </property>
  • 集合

有下面的几种方式

  • 1.包括普通的<list/>,<set/>,<map/>,和<props/>元素,分别对应着java的
    Collection类型List,Set,Map,和Properties
  • 2.还支持集合合并,这里不再演示
  • 3.支持泛型,可以使用强类型集合,利用spring的类型转换支持,
    以便强类型Collection实例的元素在被添加到之前转换为适当的类型Collection。
    在configDetail类总存在的属性如下
   private List list;

    private Set set;

    private Map map;

    private Properties properties;

    //支持泛型的集合,支持类型转换
    private Map<String,Float> accounts;

具体的xml配置如下

<property name="list">
            <list>
                <value>list</value>
                <ref bean="target"/>
            </list>
        </property>

        <property name="set">
            <set>
                <value>set</value>
                <value>set</value>
                <value>set1</value>
            </set>
        </property>

        <property name="map">
            <map>
                <entry key="map1" value="map1"></entry>
                <entry key="map1" value="map2"></entry>
                <entry key="map3" value="map3"></entry>
            </map>
        </property>

        <property name="properties">
            <props>
                <prop key="prop" >prop</prop>
                <prop key="prop1">prop1</prop>
            </props>
        </property>
        
        <property name="accounts">
            <map>
                <entry key="one" value="9.99"/>
                <entry key="two" value="2.75"/>
                <entry key="six" value="3.99"/>
            </map>
        </property>
  • 空值和空字符串
1.设置空字符串 ,配置如下
 <property name="email" value=""/>
2.设置空值,配置如下
<property name="email">
     <null/>
 </property>
  • 复合属性

举个例子:
ConfigDetail有个属性为compositeProperties,compositeProperties的所在对象有bob属性,bob属性所在的对象有sammy属性,最终sammy被赋值。
在xml的配置如下,但是需要注意compositeProperties对象和bob对象必须存在
<property name="compositeProperties.bob.sammy" value="sammy"/>
现在来模拟这种关系

/**
 * @Project: spring
 * @description:  模拟复合属性   CompositeProperties对象有个Bob,Bob有个sammy属性
 * @author: sunkang
 * @create: 2018-09-12 19:47
 * @ModificationHistory who      when       What
 **/
public class CompositeProperties {
    private Bob bob;

    public Bob getBob() {
        return bob;
    }
    public void setBob(Bob bob) {
        this.bob = bob;
    }
}
class Bob{
    private String sammy;

    public String getSammy() {
        return sammy;
    }

    public void setSammy(String sammy) {
        this.sammy = sammy;
    }
}

在ConfigDetail中存在复合组件compositeProperties

    private CompositeProperties compositeProperties;

具体的xml配置

  <bean name="compositeProperties" class="com.spring.beanDependency.configDetail.CompositeProperties"></bean>
  <bean name="bob" class="com.spring.beanDependency.configDetail.Bob"></bean>
  <bean id="configDetail" class="com.spring.beanDependency.configDetail.ConfigDetail" >
       <!--compositeProperties对象和bob对象必须存在-->
        <property name="compositeProperties" ref="compositeProperties"/>
        <property name="compositeProperties.bob" ref="bob"/>
        <property name="compositeProperties.bob.sammy" value="sammy"/>

 </bean>
  • 带有p空间的xml配置方式和带有c-namespace的XML
  • 1.p命名空间xml的命名空间需要在xml引用头加上xmlns:p="http://www.springframework.org/schema/p"
    在对应的xml配置如下:下面的p_namespace是p_namespace的一个属性
    <bean id="configDetail" class="com.spring.beanDependency.configDetail.ConfigDetail" p:p_namespace="p-namespace">
  • 2.带有c-namespace的XML ,需要在引用头加上>xmlns:c="http://www.springframework.org/schema/c"
    在xml的配置如下例如:
    <bean id="c-namespace" class="java.lang.String" c:_0="13"></bean>

3.使用依赖

举个例子,有个Examplebean类需要依赖manager类,也就是manager需要在Examplebean类先初始化,由于spring中的xml的bean的加载顺序是根据xml配置的先后进行加载的,如果需要依赖的bean对象放在后面,可能会造成不正确的加载顺序,导致错误,如果要强调配置依赖关系需要加上depends-on属性

代码如下

/**
 * @Project: spring
 * @description: manage 类   需要先初始化的类
 * @author: sunkang
 * @create: 2018-09-12 21:10
 * @ModificationHistory who      when       What
 **/
public class Manager {
    public Manager() {
        System.out.println("我是管理者,我需要先初始化");
    }
}
/**
 * @Project: spring
 * @description:  Examplebean类 ,需要依赖manager类
 * @author: sunkang
 * @create: 2018-09-12 21:10
 * @ModificationHistory who      when       What
 **/
public class Examplebean {

    public Examplebean() {
        System.out.println("我是一个bean");
    }

    public void lazyDispaly(){
        System.out.println("我是一个bean,我会懒初始化");
    }
}

在spring-dependson.xml中的配置如下

<bean name="examplebean" class="com.spring.beanDependency.dependson.Examplebean" depends-on="manager1,manager2"/>

    <bean name="manager1" class="com.spring.beanDependency.dependson.Manager"/>

    <bean name="manager2" class="com.spring.beanDependency.dependson.Manager"/>

测试类如下:

public class dependsonTest {

    public static void main(String[] args) {
        //没有配置懒加载的会在ClassPathXmlApplicationContext启动时隐式的初始化
        //有依赖的先初始化
        ApplicationContext context = new ClassPathXmlApplicationContext("beanDependency/spring-dependson.xml");
    }
}

测试结果如下:通过结果可以看出是,加上了depends-on之后强调了依赖关系,depends-on所指明的bean会先初始化

我是管理者,我需要先初始化
我是管理者,我需要先初始化
我是一个bean

3.懒加载

懒加载 ,在容器启动时并不会立即初始bean,而是在调用getBean方法才加载bean
有两种配置方式:

  • 在bean标签使用 lazy-init="true"
  • 在 beans标签使用 default-lazy-init="true",默认所有的bean都是延迟初始化

引用的还是上面的Examplebean和manager类,但是有所不同的是配置的变化,在属性上加了lazy-init这个属性

<bean name="lazybean" class="com.spring.beanDependency.dependson.Examplebean" 
lazy-init="true">
    </bean>

进行下面的测试

public class dependsonTest {

    public static void main(String[] args) {

        //没有配置懒加载的会在ClassPathXmlApplicationContext启动时隐式的初始化
        //有依赖的先初始化
        ApplicationContext context = new ClassPathXmlApplicationContext("beanDependency/spring-dependson.xml");
       System.out.println("默认是单例,没有配置懒加载属性的会立即初始化,依赖的bean会先初始化");
        //懒加载,在调用getBean方法的同时才加载bean
        //配置方式一种是 在bean标签使用 lazy-init="true"
        //    第二种可以在  beans标签使用  default-lazy-init="true",默认所有的bean都是延迟初始化
        Examplebean lazybean =   context.getBean("lazybean",Examplebean.class);
        System.out.println("-------");
        lazybean.lazyDispaly();
    }
}

测试结果如下: 可以发现context 启动时,容器并没有调用Examplebean 的构造方法,而是调用getBean的时候,对象初始化,于是我是一个bean被打印出来

默认是单例,没有配置懒加载属性的会立即初始化,依赖的bean会先初始化
我是一个bean
-------
我是一个bean,我会懒初始化

5.自动装配

我估计很多人并不了解xml的自动装配的配置,的确我之前对于xml如何装配的不太了解
比如一个接口有多个实现,我想实现把其中的一个bean实现装配到另外一个bean中,此时该如何写

再次之前需要了解一下自动装配的模式有哪些:

Mode Explanation
no 默认是没有装配模式的
byName 通过属性名称来装配,也就是bean的名称和类中的属性的名称保持一致就可以装配
byType 通过类型来进行装配,当bean的配置找到多个与实际类的类型一样时,此时会抛出错误,如果在配置中没有找到一个,则说明事情也不会发生
constructor 类似于byType,通过构造函数进行配置,如果容器中没有构造函数匹配的bean,会引发致命的错误

autowire-candidate="true" 描述被装配对象,是作为装配对象的候选人
primary="true" 描述被装配对象,是作为装配对象的首要的候选人
autowire="byType" 描述装配对象,是通过类型来装配的

演示如下:
存在Dispaly接口,有两个具体的实现DisplayA,DisplayB,Holder对象含有Dispaly接口的引用,那么对于Holder对象如何实现自动装配呢,DisplayA和DisplayB该装配哪一个呢?

/**
 * @Project: spring
 * @description: Dispaly  接口
 * @author: sunkang
 * @create: 2018-09-12 22:19
 * @ModificationHistory who      when       What
 **/
public interface Dispaly {
    String  display();
}
/**
 * @Project: spring
 * @description: DisplayA 
 * @author: sunkang
 * @create: 2018-09-12 22:19
 * @ModificationHistory who      when       What
 **/
public class DisplayA implements Dispaly {
    @Override
    public String display() {
        return "我是diasplayA";
    }
}
/**
 * @Project: spring
 * @description:
 * @author: sunkang
 * @create: 2018-09-12 22:20
 * @ModificationHistory who      when       What
 **/
public class DisplayB implements Dispaly {
    @Override
    public String display() {
        return "我是displayB";
    }
}
/**
 * @Project: spring
 * @description:
 * @author: sunkang
 * @create: 2018-09-12 22:20
 * @ModificationHistory who      when       What
 **/
public class Holder {

    private Dispaly dispaly;

    public Dispaly getDispaly() {
        return dispaly;
    }

    public void setDispaly(Dispaly dispaly) {
        this.dispaly = dispaly;
    }
}

对于要装配的对象来说,他们是等待装配的候选人,需要用到autowire-candidate来修饰,是否是装配的候选人,当存在多个候选人此时会报错,如果在多个候选人可以有个primary来修饰自己是第一候选人,即使存在多个候选人也轮不到他们来装配

在spring-autowiring.xml中存在配置如下,这里只配置了一个候选人displayB,holder对象通过类型来装配,可以知道displayB被知道装配了

 <bean id="displayA" class="com.spring.beanDependency.autowiring.DisplayA" autowire-candidate="false"/>


    <bean id="displayB" class="com.spring.beanDependency.autowiring.DisplayB" autowire-candidate="true"/>

    <bean id="holder"  class="com.spring.beanDependency.autowiring.Holder" autowire="byType"/>

如果此时存在DisplayB和DisplayA候选人,dispaly被申明为primary,可以知道他是首选的候选人,而且holder1是通过属性名称来装配,可以知道dispaly被装配

    <bean id="displayB" class="com.spring.beanDependency.autowiring.DisplayB" autowire-candidate="true"/>
    <bean id="dispaly" class="com.spring.beanDependency.autowiring.DisplayA" primary="true"/>
    <bean id="holder1"  class="com.spring.beanDependency.autowiring.Holder" autowire="byName"/>

6.方法注入

Spring提供两种机制去注入方法,分别是

  • Lookup method inject
  • Arbitrary method replacement

Lookup method inject只提供返回值注入,Arbitrary method replacement可以替换任意方法来达到注入。

+ Lookup method inject
有时我们需要在一个bean A中调用另一个bean B的方法,通常我们会添加一个字段,然后使用依赖注入把bean B的实例注入到这个字段上。这种情况下在bean A 和 bean B都是singleton时没问题,但是在 bean A是singleton和bean B是非singleton时就可能出现问题。因为bean B为非singleton , 那么bean B是希望他的使用者在一些情况下创建一个新实例,而bean A使用字段把bean B的一个实例缓存了下来,每次都使用的是同一个实例。

>先来一个实例来演示
>现在有一个Fruit的接口,内面有个获取水果名称fruitName的方法,现在有两个实体类,Apple和Bananer,还有一个水果盘FruitPlate来决定是否装什么水果,要实现每次从水果盘取得的水果都是不一样的,此时水果盘是单例,而具体的是的水果是原型模式

**
 * @Project: spring
 * @description:  水果的接口
 * @author: sunkang
 * @create: 2018-09-12 22:50
 * @ModificationHistory who      when       What
 **/
public interface Fruit {
    String fruitName();
}
/**
 * @Project: spring
 * @description: 苹果
 * @author: sunkang
 * @create: 2018-09-12 22:51
 * @ModificationHistory who      when       What
 **/
public class Apple implements Fruit {
    @Override
    public String fruitName() {
        return "我是苹果";
    }
}
/**
 * @Project: spring
 * @description: 香蕉
 * @author: sunkang
 * @create: 2018-09-12 22:51
 * @ModificationHistory who      when       What
 **/
public class Bananer implements Fruit{
    @Override
    public String fruitName() {
        return "我是香蕉";
    }
}
/**
 * @Project: spring
 * @description: 水果盘
 * @author: sunkang
 * @create: 2018-09-12 22:52
 * @ModificationHistory who      when       What
 **/
public  abstract class   FruitPlate {

    public abstract Fruit getFruit();

}

在spring-methodInjection.xml的配置如下

   <bean id="apple" class="com.spring.beanDependency.methodInjection.Apple" scope="prototype"/>

    <bean id="bananer" class="com.spring.beanDependency.methodInjection.Bananer" />
    <bean id="fruitplate" class="com.spring.beanDependency.methodInjection.FruitPlate">
        <lookup-method name="getFruit" bean="apple"/>
    </bean>

在实现测试之前,在来讲解另外一种方式的实现,比如我想把水果盘的苹果全部替换成香蕉,该如何实现

  • Arbitrary method replacement
    需要改写香蕉的实体类,让他实现MethodReplacer的接口,改装后的香蕉类如下:
/**
 * @Project: spring
 * @description: 香蕉
 * @author: sunkang
 * @create: 2018-09-12 22:51
 * @ModificationHistory who      when       What
 **/
public class Bananer implements Fruit, MethodReplacer {
    @Override
    public String fruitName() {
        return "我是香蕉";
    }
    @Override
    public Object reimplement(Object o, Method method, Object[] objects) throws Throwable {
        return fruitName();
    }
}

在spring-methodInjection.xml的对应的配置如下:

  <bean id="bananer" class="com.spring.beanDependency.methodInjection.Bananer" />
   <bean id="appleReplaceToBananer" class="com.spring.beanDependency.methodInjection.Apple">
        <replaced-method name="fruitName" replacer="bananer"/>
    </bean>

对两种注入的方式进行测试,测试代码如下:

/**
 * @Project: spring
 * @description: 方法注入的测试
 * @author: sunkang
 * @create: 2018-09-12 23:05
 * @ModificationHistory who      when       What
 **/
public class MethodinjectTest {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("methodInjection/spring-methodInjection.xml");

        //两次调用getFruit()方法,发现两个地址不一样
        //为了让fruitPlate单例,每次调用getFruit()都是不同的对象,需要用到lookup-method
        FruitPlate fruitPlate =  context.getBean("fruitplate",FruitPlate.class);
        System.out.println(fruitPlate.getFruit());
        System.out.println(fruitPlate.getFruit());

        //这里是把apple的fruitName方法替换为香蕉的方法
        Fruit appleReplaceToBananer =  context.getBean("appleReplaceToBananer",Fruit.class);
        System.out.println(appleReplaceToBananer.fruitName());
    }
}

测试结果如下:可以发现,每次从fruitplate水果盘取出的水果不一样了,实现了单例中的属性对象是多例的情况,而在appleReplaceToBananer中完成苹果的fruitName的方法到香蕉的替换

com.spring.beanDependency.methodInjection.Apple@2781e022
com.spring.beanDependency.methodInjection.Apple@57e1b0c
我是香蕉
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,313评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,369评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,916评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,333评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,425评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,481评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,491评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,268评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,719评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,004评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,179评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,832评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,510评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,153评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,402评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,045评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,071评论 2 352

推荐阅读更多精彩内容