Spring笔记(5)------依赖注入

属性注入:通过setXxx()方法注入Bean的属性值或依赖对象,它的灵活性较高,使用率高。

看例子:

public class Car {
	private String brand;
	
	private String color;
	
	private String maxSpeed;

	public String getBrand() {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}

	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	public String getMaxSpeed() {
		return maxSpeed;
	}

	public void setMaxSpeed(String maxSpeed) {
		this.maxSpeed = maxSpeed;
	}
	
	
}

再看Bean.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:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
	
	<bean id="car" class="com.baobaobao.Car" >
		<property name="brand" value="红旗CA"></property>
		<property name="color" value="黑色"></property>
		<property name="maxSpeed" value="200"></property>
	</bean>
	
</beans>

属性注入要求提供一个默认的构造函数,并为需要注入的属性提供对应的setter()方法,Spring先调用Bean的默认构造函数实例化Bean对象,然后通过反射调用setter方法注入属性值。

并且Spring只检查Bean中是否有 对应的setter方法,对于该Bean中是否有对应的属性变量则不要求,例如:

package com.baobaobao;

public class Car {
	private String brand;
	
	private String color;
	

	public String getBrand() {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}

	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	

	public void setMaxSpeed(String maxSpeed) {
		System.out.println("speed的setter......");
	}
	
	
}

配置文件跟上面一样,没有speed属性,依旧可以,但一般情况我们预定俗称提供同名的成员变量。

构造函数注入:

构造函数注入是除了属性注入以外另一种常用注入方式,它可以保证一些必要的属性在Bean实例化时就得到设置,保证了Bean在实例化后就可以使用。

1)按类型匹配入参:

如果要任何可用的Car对象都必须提供brand和price的值,如果使用属性注入的方式只能在人为配置时提供保证而无法在语法级别提供保证,这时候构造函数注入就派上用场了。使用构造函数注入的前提是必须提供带参的构造函数。如下:

package com.baobaobao;

public class Car {
	private double price;
	
	private String color;
	

	

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	

	public Car(double price,String color){
		this.price = price;
		this.color = color;
	}
	
}

加入一个带参的构造器,再看配置文件:

<?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:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
	
	<bean id="car" class="com.baobaobao.Car" >
		<constructor-arg type="double">
			<value>200000</value>
		</constructor-arg>
		<constructor-arg type="java.lang.String">
			<value>红色</value>
		</constructor-arg>
	</bean>
	
</beans>

在<constructor-arg>元素中有一个type属性,它为Spring提供了判断配置项和构造函数入参对应关系的信息。而且Spring标签属性跟元素无关的策略,保障了配置文件的正确性。例如:

<?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:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
	
	<bean id="car" class="com.baobaobao.Car" >
	
	<constructor-arg type="java.lang.String">
			<value>红色</value>
		</constructor-arg>
		<constructor-arg type="double">
			<value>200000</value>
		</constructor-arg>
		
	</bean>
	
</beans>
顺序改变,依旧不会影响。。。。

2)按索引匹配入参:

如果通过type属性来区分属性显然不现实,如果俩属性类型相同就完蛋了,这是我们可以通过入参索引进行确定。

因为Java反射机制无法记住构造函数的入参名,因此我们无法指定构造函数的入参名来进行构造函数注入的配置,只能通过入参类型和入参索引间接地确定构造函数配置项和入参的对应关系。如下:

package com.baobaobao;

public class Car {
	private double price;
	
	private String color;
	
	private String brand;
	
	
	

	public String getBrand() {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	

	public Car(double price,String color,String brand){
		this.price = price;
		this.color = color;
		this.brand = brand;
	}
	
}

配置文件如下:

<?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:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
	
	<bean id="car" class="com.baobaobao.Car" >
		<constructor-arg index="0">
			<value>200000</value>
		</constructor-arg>
		<constructor-arg index="1">
			<value>红色</value>
		</constructor-arg>
		<constructor-arg index="2">
			<value>奥迪</value>
		</constructor-arg>
	</bean>
	
</beans>

索引从0开始,表示着在构造函数入参的顺序索引。

3)联合使用类型和索引匹配入参:

有时候类型跟索引要联合出马才能确定配置项跟构造函数入参的对应关系,如下:

public class Car {
	
	private double price;
	
	private String color;
	
	private String brand;
	
	private int maxSpeed;
	
	
	
	public int getMaxSpeed() {
		return maxSpeed;
	}

	public void setMaxSpeed(int maxSpeed) {
		this.maxSpeed = maxSpeed;
	}

	public String getBrand() {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	

	public Car(double price,String color,String brand){
		this.price = price;
		this.color = color;
		this.brand = brand;
	}
	
	public Car(String color,int maxSpeed,String brand){
		this.color = color;
		this.maxSpeed = maxSpeed;
		this.brand = brand;
	}
	
}

该Bean有两个重载的构造函数,他们都有3个入参,如果只按索引肯定没法确定对应关系,可以type跟index结合用:如下:

<?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:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
	
	<bean id="car" class="com.baobaobao.Car" >
		<constructor-arg index="0" type="java.lang.String">
			<value>红色</value>
		</constructor-arg>
		<constructor-arg index="1" type="int">
			<value>200</value>
		</constructor-arg>
		<constructor-arg index="2" type="java.lang.String">
			<value>奥迪</value>
		</constructor-arg>
	</bean>
	
</beans>

这个配置即对应上面Car的第二个构造函数。。。。

4)通过自身类型反射匹配入参:

如果Bean构造函数入参的类型是可辨别的(非基础数据类型且入参类型各异),由于java反射机制可以获取构造函数入参的类型,即使构造函数注入的配置不提供类型和索引,Spring依旧可以完成构造函数注入工作。

如下:

<?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:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
	
	<bean id="boss" class="com.baobaobao.Boss">
		<constructor-arg>
			<value>James</value>
		</constructor-arg>
		<constructor-arg>
			<ref bean="car"/>
		</constructor-arg>
	</bean>
	
	<bean id="car" class="com.baobaobao.Car" >
		<constructor-arg index="0" type="java.lang.String">
			<value>红色</value>
		</constructor-arg>
		<constructor-arg index="1" type="int">
			<value>200</value>
		</constructor-arg>
		<constructor-arg index="2" type="java.lang.String">
			<value>奥迪</value>
		</constructor-arg>
	</bean>
	
</beans>

Car类跟上面的例子一样,这样既可实现注入,但如果Bean存在多个构造函数,显示的指定type和index依然是一种良好的习惯。

5)循环依赖问题:

Spring容器能够顺利实例化以构造器注入配置的Bean有一个前提:Bean构造函数的入参引用的对象必须已经准备就绪,由于这个机制限制,如果两个Bean都采用构造函数注入,而且通过构造函数入参引用对方,就会发生类似于线程死锁的循环依赖问题。

工厂方法注入:

1)非静态工厂方法

先提供一个工厂类,如下:

package cn.com.demo.po;

public class CarFactory {
	public Car createAodiCar(){
		Car car = new Car();
		car.setBrand("奥迪A4");
		return car;
	}
}
然后applicationContext.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-3.1.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
		<bean id="carFactory" class="cn.com.demo.po.CarFactory"></bean>
		<bean id="car5" factory-bean="carFactory" factory-method="createAodiCar"></bean>
</beans>

然后使用如下的测试类跑一下:

public class SpringRun {
	public static void main(String[] args) {
		ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
		Car car = ac.getBean("car5", Car.class);
		System.out.println(car.getBrand());
	}
}

完美运行!!!~

由于CarFactory不是静态的,所以首先要定义一个工厂类的Bean,然后通过factory-bean引入工厂类实例,再通过factory-method指定对应的工厂方法。

2)静态工厂方法:

很多工厂方法都是静态的,不需要用户创建工厂实例就可以调用他们,修改一下CarFactory,如下:

public class CarFactory {
	public static Car createAodiCar(){
		Car car = new Car();
		car.setBrand("奥迪A4");
		return car;
	}
}

配置文件如下:

<?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-3.1.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
		
		<bean id="car6" class="cn.com.demo.po.CarFactory" factory-method="createAodiCar" />
</beans>

当使用了静态工厂类型方法后,用户无需再配置文件中定义工厂类的Bean了,只需要按如上配置即可,直接在bean的class里指定工厂类,然后通过factory-method指定工厂方法。


关于选择注入方式:

仁者见仁,智者见智,例如构造函数注入的优点:

1)可以保证Bean需要的属性在实例化后就已经设置好,避免一些重要的属性没有提供,导致一个无用的Bean实例产生。

2)不需要为每个属性提供setter方法,减少了类中方法的个数。

3)更好的封装变量,没有提供setter方法,可以避免外部错误的引用。

而它的缺点也有:

1)如果一个类属性众多,那么构造函数签名会变得庞大,可读性差。

  2)灵活性差,如果有些属性时可选的情况下,如果构造器注入,需要为这些属性提供一个null值。

3)如果构造函数多的话,配置文件为了区别开来这些构造函数,配置变得复杂。

4)构造函数有时候会造成循环依赖问题。

用户完全可以根据这两种注入方式的优缺点在特点的情况下选择,没有强制规定,不过工厂方法因为引入了额外的类跟方法,不推荐,Spring已经实现了工厂模式的所有功能,不需要画蛇添足了。。。。


内容概要:本文详细探讨了基于MATLAB/SIMULINK的多载波无线通信系统仿真及性能分析,重点研究了以OFDM为代表的多载波技术。文章首先介绍了OFDM的基本原理和系统组成,随后通过仿真平台分析了不同调制方式的抗干扰性能、信道估计算法对系统性能的影响以及同步技术的实现与分析。文中提供了详细的MATLAB代码实现,涵盖OFDM系统的基本仿真、信道估计算法比较、同步算法实现和不同调制方式的性能比较。此外,还讨论了信道特征、OFDM关键技术、信道估计、同步技术和系统级仿真架构,并提出了未来的改进方向,如深度学习增强、混合波形设计和硬件加速方案。; 适合人群:具备无线通信基础知识,尤其是对OFDM技术有一定了解的研究人员和技术人员;从事无线通信系统设计与开发的工程师;高校通信工程专业的高年级本科生和研究生。; 使用场景及目标:①理解OFDM系统的工作原理及其在多径信道环境下的性能表现;②掌握MATLAB/SIMULINK在无线通信系统仿真中的应用;③评估不同调制方式、信道估计算法和同步算法的优劣;④为实际OFDM系统的设计和优化提供理论依据和技术支持。; 其他说明:本文不仅提供了详细的理论分析,还附带了大量的MATLAB代码示例,便于读者动手实践。建议读者在学习过程中结合代码进行调试和实验,以加深对OFDM技术的理解。此外,文中还涉及了一些最新的研究方向和技术趋势,如AI增强和毫米波通信,为读者提供了更广阔的视野。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值