spring入门学习笔记第三课--spring的注入

spring的一个核心功能就是依赖注入,有的叫依赖注入(DI),也有的叫控制反转(IOC),但实际上在某种程度上,他们是差不多的。

我学习spring接触到的第一个概念就是DI,

通俗的解释就是:

在我们常规编程中,如果需要使用某个的方法,我们通常会new一个该对象的实例,然后调用方法,就像这样:

现有A和B两个类,我们想要在B类中调用的methodA方法。

Object A
public class A{
/**
 *这是我们想要调用的方法
 **/
public void methodA(){
 //逻辑....
}
}
}

我们通常在B类中会这样用:

public class B{
public void methodB(){

//我们会先new一个A的对象
A a=new A();
//然后调用A的方法
a.methodA();

}

}
这种是比较常规的方法,即:如果我们使用某个对象的方法,我们需要手动创建这个对象。

但是IOC就提供了另外一种思维方式,就是不在由我们去创建这个类,而是由spring去创建这个类。

举一个生活中简单的例子,

在以前,如果我们需要一件新衣服,我们往往会这样做:

去布店裁点布,然后我们回家自己做。

也就是说,如果我们需要新衣服,我们需要自己做。

但是现在就不同了,现在如果我们需要一件新衣服,我们可以通过各种渠道购入,比如网上购物,比如商场。

这样,当我们需要新衣服的时候,我们就不需要自己去做了,相对于以前,不仅省了大量的时间,而且衣服的款式也多种多样。

回到spring这里,其实这里spring就承担类似于商场或者网店这样的角色,

我们不需要自己去做衣服,我们只要告诉spring我们需要什么样的衣服,spring会自动给我们提供。

如果放到代码里,大概就是这个样子的。

首先,我们需要构建一个spring项目:

项目的结构如下:


首先定义一个服装的接口,这个接口定义了如何展示这件衣服:

package com.panda.clothes.inter;
/**
 * 定义服装接口
 * @author Panda
 *
 */
public interface BaseClothes {
	/**
	 * 展示衣服的方法
	 */
	public void showClothes();

}
然后,编写两个类,分别实现服装接口。

package com.panda.clothes.inter.impl;

import com.panda.clothes.inter.BaseClothes;
/**
 * 西装类
 * 该类实现了衣服的接口
 * @author Panda
 *
 */
public class BusinessSuit implements BaseClothes {

	public void showClothes() {
		System.out.println("Clothes`s Name:"+"BusinessSuit");
		System.out.println("Clothes`s price:"+"$1000.0");
		System.out.println("Clothes`s Color:"+"black");
	}

}
package com.panda.clothes.inter.impl;

import com.panda.clothes.inter.BaseClothes;
/**
 * T恤衫类
 * 该类实现服装接口
 * @author Panda
 *
 */
public class TShirt implements BaseClothes {

	public void showClothes() {
		System.out.println("Clothes`s Name:"+"TShirt");
		System.out.println("Clothes`s price:"+"$150.0");
		System.out.println("Clothes`s Color:"+"white");
	}

}
接下来编写测试类,

首先是我们比较常用的方式:

首先构建一个实例,然后调用方法

/**
	 * 常规的使用方法
	 */
	@org.junit.Test
	public void conventionTest(){
	//首先创建一个服装对象,然后对其赋值。
		BaseClothes clothes=new BusinessSuit();
		//然后调用服装的展示方法
		clothes.showClothes();
		
	}
运行结果如下:

Clothes`s Name:BusinessSuit
Clothes`s price:$1000.0
Clothes`s Color:black

但是,如果我们突然不想要西装了,我们想要T恤,我们就需要对代码修改

	/**
	 * 常规的使用方法
	 */
	@org.junit.Test
	public void conventionTest(){
	//如果此时我们不想要西装,我们想要T恤。我们就需要实例化T恤而不是西装。
		//BaseClothes clothes=new BusinessSuit();
		//重新构造
		BaseClothes clothes=new TShirt();
		//然后调用服装的展示方法
		clothes.showClothes();
		
	}
运行结果如下:

Clothes`s Name:TShirt
Clothes`s price:$150.0
Clothes`s Color:white

这样我们就会发现,当我们对衣服需要变更时,我们需要修改代码。如果只有两件衣服还好一点,但是当业务逻辑更加复杂时,我们很可能都不知道自己需要改多少代码。

但是spring为我们提供了一种优秀的解决办法,也就是DI。

spring的DI有三种,

分别是:

1.接口注入

2.构造注入

3.set注入

首先我们展示第一种注入方式,接口注入,如果我们需要使用接口注入的话,需要提供一个接口,该接口提供被调用类的初始化方法。

package com.panda.clothes.test;

import com.panda.clothes.inter.BaseClothes;

public interface InterfaceInject {

    public void CreateClothes(BaseClothes clothes);
       public BaseClothes getClothes();
}


然后,任何需要使用clothes实例的类,都要继承这个类

package com.panda.clothes.test;

import com.panda.clothes.inter.BaseClothes;

public class InterfaceInjectImpl implements InterfaceInject {
    private BaseClothes clothes;
    
    public void CreateClothes(BaseClothes clothes) {
        this.clothes = clothes;
    }
    public BaseClothes getClothes(){
        
        return this.clothes;
        
    }
}
最后,我们编写测试类。
package com.panda.clothes.test;

import com.panda.clothes.inter.BaseClothes;
import com.panda.clothes.inter.impl.TShirt;

public class InterfaceTest {
//首先获取clothes的实例
InterfaceInject ifi=new InterfaceInjectImpl();
@org.junit.Test
public void test(){
    //提供clothes的实例
    ifi.CreateClothes(new TShirt());
    //获取clothes的实例
    BaseClothes clothes=ifi.getClothes();
    //调用clothes的展示方法
    clothes.showClothes();
}
}

输出结果如下:

Clothes`s Name:TShirt
Clothes`s price:$150.0
Clothes`s Color:white
这样做有什么作用呢?

在我们常规的方法中,调用类直接依赖被调用类,使用接口注入我们就可以将依赖分离到接口层次,然后具体的实现我们可以通过配置文件或其他方式来加载。

但是这种方式依然具备很强的侵略性,所以实际应用有限。

其实关于接口注入,我也是有点迷糊,似懂非懂的感觉,做个标记,之后等完全弄清楚再回来补一个详细的。


2017/03/03补充:接口注入和注入接口的区别

整理这篇内容的时候,在这我遇到一个问题,就是接口注入和注入接口有什么本质的区别,毕竟看起来这个东西最终的实现和注入接口的方式是一样的,而且还多了一层,更复杂了.

关于这个问题问了好多人,今天终于获得了一个比较通俗的解释,

使用接口注入这种方式,我们可以在中转接口中,定义一些指定的业务处理,做一些校验等操作,类似于服务定位模式.

比直接注入接口多了一层封装.


spring中使用最多的方式就是set注入,setter注入通过提供属性值的getter/setter方法来注入需要的实例。

继续使用之前的BaseClothes接口和BusinessSuit以及TShirt实例。

然后我们新建一个测试类:

在测试类中提供一个BaseClothes参数,并提供她的getter/setter方法。

package com.panda.clothes.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.panda.clothes.inter.BaseClothes;

public class SetterTest {
    //提供BaseClothes字段
private BaseClothes clothes;
    //提供BaseClothes的getter/setter方法
public BaseClothes getClothes() {
    return clothes;
}

public void setClothes(BaseClothes clothes) {
       System.out.println("set注入调用属性的setter方法");
    this.clothes = clothes;
}
@org.junit.Test
public void Test(){
    ApplicationContext atc=new ClassPathXmlApplicationContext("spring-demo.xml");
    SetterTest ses=(SetterTest) atc.getBean("setterTest");
    ses.getClothes().showClothes();
}
}
之后我们在SRC下新建一个spring-demo.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="setterTest" class="com.panda.clothes.test.SetterTest">
	
			<property name="clothes" ref="businessSuit"></property>
	</bean>
	<!-- 服装 -->
	<!-- 西装 -->
	<bean id="businessSuit" class="com.panda.clothes.inter.impl.BusinessSuit" />
	<!-- T恤 -->
	<bean id="tShirt" class="com.panda.clothes.inter.impl.TShirt"></bean>
	
</beans>
运行测试类:
set注入调用属性的setter方法
Clothes`s Name:BusinessSuit
Clothes`s price:$1000.0
Clothes`s Color:black

这种在配置文件中通过property属性进行配置则默认采用的set注入。

最后一种注入方式为构造注入:

只需要稍微修改一下配置文件和测试类:

测试类去除getter/setter方法,添加一个构造方法

public class SetterTest {
	//提供BaseClothes字段
private BaseClothes clothes;
	//提供BaseClothes的getter/setter方法
public  SetterTest(BaseClothes clothes) {
	// TODO Auto-generated constructor stub
	this.clothes=clothes;
}
public static void main(String []args){
	ApplicationContext atc=new ClassPathXmlApplicationContext("spring-demo.xml");
	SetterTest ses=(SetterTest) atc.getBean("setterTest");
	ses.clothes.showClothes();
}

配置文件:

<?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="setterTest" class="com.panda.clothes.test.SetterTest">
	 <constructor-arg index="0" ref="tShirt" />
	</bean>
	<!-- 服装 -->
	<!-- 西装 -->
	<bean id="businessSuit" class="com.panda.clothes.inter.impl.BusinessSuit" />
	<!-- T恤 -->
	<bean id="tShirt" class="com.panda.clothes.inter.impl.TShirt"/>

</beans>
这种通过constructor-arg注入的方法叫做构造注入,他是通过构造方法进行注入。

这三种方法常用的是set注入也叫设置注入,

通过这种方法,我们可以直观明确的了解我们注入的是什么,但是因为我们提供了setter方法,所以我们不能确定相关的数据成员会不会被改变。

而通过构造注入的方法,一方面符合了java的编码规则,在类创建是就得到一个完整的实例,另一方面我们也可以通过构造参数的顺序来控制我们实例化的顺序,但是这种方法当我们需要实例化较多数据时,构造器会比较臃肿,而且参数太多,也不太容易记忆。




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值