三种方法实现依赖注入

1 使用XML文件实现依赖注入

1.1 setter实现依赖注入

通过<bean>标签下的<property>标签进行注入。

  1. 若要注入简单值,则通过<property>的value属性
  2. 若要注入引用其他的bean的id或name,则使用<property>的ref属性
  3. 若要注入集合,则<property>下有对应<set>、<list>、<map>、<props>。若注入简单值,直接使用<value>;如果集合中是引用的其他bean,使用<ref>
  4. 对于map存储的是键值对,应使用<enter>标签。如果键是简单值,则使用key属性指定其值,如果是引用的其他bean,使用key-ref属性指定bean的id或name;如果值是简单值,则使用value属性指定其值,如果是引用的其他bean,使用value-ref属性指定bean的id或name
  5. 注入Properties集合,可以使用<props>或<value>

1.1.1 注入简单值(基本数据类型或字符串)

<bean id="person" class="com.qdu.bean.Girl">
	
    <property name="name" value="小明" />

</bean>

 1.1.2 注入引用的其他bean(引用类型)

<bean id="person" class="com.qdu.bean.Girl">
	<property name="axe" ref="fuzi" />
	<property name="pet" ref="chongwu" />
</bean>

1.1.3 注入集合(Set、List、Map、Properties) 

<bean id="company" class="com.qdu.bean.Company">
	<property name="companyName" value="二维数组有限公司" />
	<property name="companyAddress" ref="addr3" />
	<property name="branchNames">
		<!-- set标记用于注入set集合的值 -->
		<set>
			<!-- 如果集合中是引用的其他bean,使用ref标记,通过bean指定引用的bean的id或name -->
			<!-- <ref bean="id或name" /> -->
			<!-- 如果集合中是简单值,使用value指定值即可 -->
			<value>山东分公司</value>
			<value>山西分公司</value>
			<value>广东分公司</value>
			<value>广西分公司</value>
			<value>海南分公司</value>
		</set>
	</property>
	<property name="partnerNames">
		<list>
			<!-- 如果集合中是引用的其他bean,使用ref标记,通过bean指定引用的bean的id或name -->
			<!-- <ref bean="id或name" /> -->
			<!-- 如果集合中是简单值,使用value指定值即可 -->
			<value>Oracle</value>
			<value>Microsoft</value>
			<value>IBM</value>
			<value>Google</value>
		</list>
	</property>
	<property name="employeeList">
		<list>
			<!-- 如果集合中是引用的其他bean,使用ref标记,通过bean指定引用的bean的id或name -->
			<ref bean="emp1" />
			<ref bean="emp2" />
		</list>
	</property>
	<property name="branchManagers">
		<map>
			<!-- entry用于指定一项数据的注入 -->
			<!-- 如果键是简单值,则使用key指定其值,如果是引用的其他bean,使用key-ref指定bean的id或name -->
			<!-- 如果值是简单值,则使用value指定其值,如果是引用的其他bean,使用value-ref指定bean的id或name -->
			<entry key="山东分公司" value-ref="emp1" />
			<entry key="山西分公司" value-ref="emp2" />
		</map>
	</property>
	<!-- 注入Properties集合,可以使用props标记或value标记 -->
	<property name="extraInfo1">
		<props>
			<prop key="registeredCapital">1000000</prop>
			<prop key="legalPerson">小胖</prop>
			<prop key="type">Joint venture</prop>
		</props>
	</property>
	<property name="extraInfo2">
		<value>
			registeredCapital=2000000
			legalPerson=Allen
			type=Joint venture
		</value>
	</property>
</bean>

注意:在相应类中,必须要给对应的属性生成setter访问器,因为要使用setXXX()方法来注入/设置需要的值 

诸如在Girl类中:

public class Girl implements Person {

	private String name;
	private Axe axe;
	private Pet pet;
	
	public Girl() {
	}

	public Girl(String name, Axe axe, Pet pet) {
		this.name = name;
		this.axe = axe;
		this.pet = pet;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public void setAxe(Axe axe) {
		this.axe = axe;
	}

	public void setPet(Pet pet) {
		this.pet = pet;
	}

	@Override
	public void kanChai() {

		System.out.println("Girl砍柴,力气更大!!!");
		axe.cut();
		pet.showSkill();
	}
}

1.2 构造函数实现依赖注入

通过<bean>标签下的<constructor-arg>标签实现注入。注意,如果使用setter注入,<constructor-arg>的name属性是类中的属性名;但这里使用构造函数注入,<constructor-arg>的name属性指定的是构造函数的参数的名称。也可不写参数名称,但是必须保证参数的顺序是对的。可以使用参数索引index属性(0表示第一个参数),这样参数顺序随便写。但是如果不写参数名称,也不写参数索引,则参数顺序必须正确。

  1. 注入简单值,通过value属性指定要注入的值即可
  2.  如果注入引用的其他bean,使用ref属性指定要注入的bean的id或name
  3. 若要注入集合,则<constructor-arg>下有对应<set>、<list>、<map>、<props>。若注入简单值,直接使用<value>;如果集合中是引用的其他bean,使用<ref>
  4. 对于map存储的是键值对,应使用<enter>标签。如果键是简单值,则使用key属性指定其值,如果是引用的其他bean,使用key-ref属性指定bean的id或name;如果值是简单值,则使用value属性指定其值,如果是引用的其他bean,使用value-ref属性指定bean的id或name
  5. 注入Properties集合,可以使用<props>或<value>

1.2.1 注入简单值(基本数据类型或字符串)

<bean id="addr1" class="com.qdu.bean.Address">
	<constructor-arg name="pro" value="山东" />
	<constructor-arg name="city" value="青岛" />
</bean>

使用构造函数注入,也可不写参数名称,但是必须保证参数的顺序是对的。

可以使用参数索引(0表示第一个参数),这样参数顺序随便写。

但是如果不写参数名称,也不写参数索引,则参数顺序必须正确。

<bean id="addr2" class="com.qdu.bean.Address">
	<constructor-arg index="0" value="山东" />
	<constructor-arg index="1" value="济南" />
	<constructor-arg index="2" value="泉城广场" />
</bean>

 1.2.2 注入引用的其他bean(引用类型)

<bean id="emp1" class="com.qdu.bean.Employee">
	<constructor-arg name="empId" value="E001" />
	<constructor-arg name="empName" value="小强" />
	<constructor-arg name="empSalary" value="50000" />
	<!-- 如果注入引用的其他bean,使用ref属性指定要注入的bean的id或name -->
	<constructor-arg name="address" ref="addr1" />
</bean>

1.2.3 注入集合(Set、List、Map、Properties) 

<bean id="company" class="com.qdu.bean.Company">
	<constructor-arg name="companyName" value="二维数组有限公司" />
	<constructor-arg name="companyAddress" ref="addr3" />
	<constructor-arg name="branchNames">
		<set>
			<!-- 如果集合中是简单值,使用value指定值即可 -->
			<value>山东分公司</value>
			<value>山西分公司</value>
			<value>广东分公司</value>
			<value>广西分公司</value>
			<value>海南分公司</value>
		</set>
	</constructor-arg>
	<constructor-arg name="partnerNames">
		<list>
			<value>Oracle</value>
			<value>Microsoft</value>
			<value>IBM</value>
			<value>Google</value>
		</list>
	</constructor-arg>
	<constructor-arg name="employeeList">
		<list>
			<!-- 如果集合中是引用的其他bean,使用ref标记,通过bean指定引用的bean的id或name -->
			<ref bean="emp1" />
			<ref bean="emp2" />
		</list>
	</constructor-arg>
	<constructor-arg name="branchManagers">
		<map>
			<!-- entry用于指定一项数据的注入 -->
			<!-- 如果键是简单值,则使用key指定其值,如果是引用的其他bean,使用key-ref指定bean的id或name -->
			<!-- 如果值是简单值,则使用value指定其值,如果是引用的其他bean,使用value-ref指定bean的id或name -->
			<entry key="山东分公司" value-ref="emp1" />
			<entry key="山西分公司" value-ref="emp2" />
		</map>
	</constructor-arg>
	<!-- 注入Properties集合,可以使用props标记或value标记 -->
	<constructor-arg name="extraInfo1">
		<props>
			<prop key="registeredCapital">1000000</prop>
			<prop key="legalPerson">小胖</prop>
			<prop key="type">Joint venture</prop>
		</props>
	</constructor-arg>
	<constructor-arg name="extraInfo2">
		<value>
			registeredCapital=2000000
			legalPerson=Allen
			type=Joint venture
		</value>
	</constructor-arg>
</bean>

 注意:在相应类中,必须要生成构造函数:

public class Address {

    private String province; //省
    private String city; 	 //市
    private String detailedAddress; //详细地址
    
	@Override
	public String toString() {
		return "地址::" + province + "省" + city + "市" + detailedAddress;
	}

	public Address() {
		super();
	}

	public Address(String pro, String city, String detailedAddress) {
		System.out.println("调用了带3个参数的构造函数实现依赖注入!!!");
		this.province = pro;
		this.city = city;
		this.detailedAddress = detailedAddress;
	}

	public void setProvince(String province) {
		System.out.println("setProvince()方法被调用........");
		this.province = province;
	}

	public void setCity(String city) {
		this.city = city;
	}

	public void setDetailedAddress(String detailedAddress) {
		this.detailedAddress = detailedAddress;
	}
}

1.3 自动装配

在应用程序对象之间创建和管理关联的过程叫做装配,这构成了DI的核心。以上两种方法为显示装配(显式声明Bean之间的依赖),自动装配(autowiring)不显式声明Bean之间的依赖,让容器选择合适的依赖项注入。

1.3.1 byName

 byName是按照名称自动装配,意思是要注入的属性的属性名和要注入的bean的id或name(别名)相同,即可实现按照名称自动装配。

当一个bean带有autowire byName的属性时:

  1. 将查找其类中所有的set方法名,例如setCat,获得将set去掉并且首字母小写的字符串,即cat。
  2. 去spring容器中寻找是否有此字符串名称id的对象。
  3. 如果有,就取出注入;如果没有,就报空指针异常
<bean id="person" class="com.qdu.bean.Boy" autowire="byName">

    <property name="name" value="小兰" />

</bean>

1.3.2 byType

byType是按照类型自动装配。如果要注入的属性的数据类型和容器中某个bean的类型匹配,则实现自动装配。

自动装配跟 id 无关,在配置bean 时不写 id 都不会报错。

但是 byType 的自动装配存在一个很严重的问题,因为不是通过唯一的 id 来匹配,而是通过类型来匹配,所以容器中不能存在多个相同类型的 bean,否则会抛出NoUniqueBeanDefinitionException异常。

<bean id="person" class="com.qdu.bean.Girl" autowire="byType">

	<property name="name" value="小明" />
	
</bean>

1.3.3 constructor

constructor表示使用对应的构造函数实现自动装配,所以需要生成对应的构造函数

<bean id="person" class="com.qdu.bean.Girl" autowire="constructor">

	<property name="name" value="小明" />

</bean>
public class Girl implements Person {
 
	private String name;
	private Axe axe;
	private Pet pet;
	
	@Override
	public void kanChai() {
		System.out.println("砍柴人:"+name);
		System.out.println("Girl砍柴,力气更大!!!");
		pet.showSkill();
		axe.cut();
	}
 
	public Girl() {
		super();
	}
 
	//如果使用构造函数实现自动装配,需要生成对应的构造函数
	//使用constructor实现自动装配,只要构造函数的数据类型对了即可,参数名无所谓
	public Girl(Axe a, Pet p) {
		super();
		System.out.println("带2个参数的构造函数~~~");
		this.axe = a;
		this.pet = p;
	}
 
	public void setName(String name) {
		this.name = name;
	}
 
	public void setAxe(Axe axe) {
		this.axe = axe;
	}
 
	public void setPet(Pet pet) {
		this.pet = pet;
	}
}

2 使用Java代码实现依赖注入

2.1 调用@Bean修饰的对应方法实现注入

使用Java代码进行注入,首先要先写一个Java代码的Spring配置类SpringConfig1.class

首先要注意,配置类需要用@Configuration注解修饰。而且由于我们使用的是java配置类,而不是xml配置文件,则需要使用ApplicationContext接口的AnnotationConfigApplicationContext实现类来创建容器。

ApplicationContext ctx 
	= new AnnotationConfigApplicationContext(SpringConfig.class);

使用@Bean修饰的方法注册一个bean成为spring管理的bean,方法返回的对象成为Spring管理的bean。于是, 可通过调用产生bean的方法来获取一个bean实现依赖注入。

@Configuration
public class SpringConfig1 {
	
	@Bean
	public Axe fuzi() {
		return new SteelAxe();
	}
	
	@Bean
	public Pet chongwu() {
		return new Pig();
	}
	

	@Bean
	public Person person() {
		Girl girl=new Girl();
		girl.setName("小花");
		girl.setAxe(fuzi()); //调用fuzi()方法获取的是spring管理的SteelAxe对象
		girl.setPet(chongwu()); //调用chongwu()方法获取的是spring管理的Pig对象
		return girl;
	}
}

2.2 通过方法参数获取要注入的bean 

同上,首先要有一个Spring的配置类SpringConfig2.class。仍然使用@Bean修饰的方法注册一个bean成为spring管理的bean。

这一方法与2.1不同的是,这一种直接在方法上添加对应类型的参数,使用传入的参数设置属性实现依赖注入。参数的名称和顺序无所谓,只要参数类型对了即可。

@Bean
public Person person(Pet p,Axe a) {
	Girl girl=new Girl();
	girl.setName("小花");
	girl.setAxe(a); //直接使用传入的参数进行注入即可
	girl.setPet(p); 
	return girl;
}

 3 使用注解实现依赖注入

使用注解,首先要在Spring的配置类中使用@ComponentScan开启包扫描,也别忘记@Configuration。使用注解的一个好处就是SpringConfig.class非常简单:

@Configuration
@ComponentScan("com.qdu.bean")
//@ComponentScan({"com.qdu.bean","com.qdu.service","com.qdu.dao"})
public class SpringConfig {
	
}

开启包扫描后,别忘记在每个类使用添加注解@Component,将一个类注册为spring管理的bean

在字段前使用@Autowired注解,则使用反射实现注入。@Autowired注解按照类型进行装配,如果存在多个匹配类型,会报错。@Autowired可用于构造函数前、setter方法前、其他任何用于注入的方法前或字段前。

@Component
public class Girl implements Person {

	private String name;
	
	@Autowired
	private Axe axe;
	
	@Autowired
	private Pet pet;

	public Girl() {
	}

	public Girl(String name, Axe axe, Pet pet) {
		this.name = name;
		this.axe = axe;
		this.pet = pet;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setAxe(Axe axe) {
		this.axe = axe;
	}

	public void setPet(Pet pet) {
		this.pet = pet;
	}

	@Override
	public void kanChai() {
		System.out.println("Girl砍柴,力气更大!!!");
		axe.cut();
		pet.showSkill();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值