由于这篇文档涉及的知识点有点多,于是在此写个目录:
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
我是香蕉