前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >学习Spring——依赖注入

学习Spring——依赖注入

作者头像
JackieZheng
发布2018-01-16 17:36:00
7040
发布2018-01-16 17:36:00
举报
文章被收录于专栏:JackieZhengJackieZheng

前言:

  又开始动笔开了“学习Spring”系列的头……

  其实一开始写“学习SpringMVC”的几篇文章是出于想系统的了解下Spring以及SpringMVC,因为平时在公司中虽然每天都在使用Spring相关的框架或者其他,但是绝大部分都是已经写好配置文件,做好相关配置,而我们能做的就是写一些与业务逻辑有关的Controller层面或者Service层面的代码。毕竟所做的产品成熟了,或者说框架越来越成熟了,我们对于底层原理的东西关注的就少了,认识也浅了。

  个人感觉,颇具讽刺意味的是,“SpringMVC”系列的HelloWorld篇发出去后,每日阅读量出现了比以外任何一篇都要快的尴尬式增长,如今已经成为我第一篇超过5位数阅读量的文章,汗-_-!

  本来只是想在了解了SpringMVC的套路后,稍稍的看下佟刚老师的Spring视频就算了。可是后来有网友问SpringMVC系列是否还有后续,我想了一下,那如果有的话可能就是Spring基础相关了吧;而且,有些东西只是抱着看一看的心态,最后得到的也就是看一看的反馈,一个小时又或是一天之后就完全忘得一干二净了。所以,算是一份笔记吧,这里开了个头。

  通过之前SpringMVC的学习,似乎在某些瞬间,我似乎看到了一些与自己项目中似曾相识的套路,只是之前因为项目过大,或者自己做的只是一些细微的调整,很难发现项目的大森林全貌。学习Spring的时候,我也希望能够重现类似的桥段,这样的学习就是有回报的,值得的。

  毫无意外可言,第一篇讲的还是HelloWorld(主要是依赖注入的特性)。

Spring

  Spring 是一个开源框架。

  Spring 是一个 IOC(DI) 和 AOP 容器框架(Spring的两大法宝)。

  Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性的角度而言,绝大部分Java应用都可以从Spring中受益(总而言之,Spring就是很腻害)。

  官网:https://spring.io/

HelloWorld实例对比

  首先,需要新建一个Java Project,新建完成目录结构如下:

  如你所见,这里还要一些需要用到的jar。

没有使用Spring的那一套

  不可否认,在Spring没有横空出世的时候,太阳依旧是东起西落,地球如斯旋转。大概是这个样子:

  新建HelloWorld类

代码语言:javascript
复制
public class HelloWorld {

	private String name;

        public HelloWorld() {
		System.out.println("HelloWorld's constructor...");
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public void hello(){
		System.out.println("Hello: " + name);
	}
	
}    

  新建测试方法

代码语言:javascript
复制
public class Main {
	
	public static void main(String[] args) {
		
		HelloWorld helloWorld = new HelloWorld();
		helloWorld.setName("Jackie");
                helloWorld.hello();
        }
}        

  最终你会如愿以偿的得到你期望的结果:“Hello:Jackie”

使用Spring后的这一套

  使用Spring框架后,我们不能单纯的新建两个类就完事了,怎么说也对不起框架这两个字,于是我们需要:

  新建一个Spring的配置文件beans.xml

代码语言:javascript
复制
<?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:util="http://www.springframework.org/schema/util"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
	
	<!-- 配置一个 bean -->
	<bean id="helloWorld" class="com.jackie.spring.helloworld.HelloWorld">
		<!-- 为属性赋值 -->
		<property name="name" value="Jackie"></property>
	</bean>
</beans>

  测试方法

  这里我们大致分为如下几步:

    1. 创建 Spring 的 IOC 容器

    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");

    2. 从创建的 IOC 容器中获取 bean 的实例

    HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");

    3. 使用 bean实例

    helloWorld.hello();

注意:

  • ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");实际上是容器初始化操作,包括本例子中执行helloWorld的构造函数以及执行setName方法
  • 这里的ctx.getBean("helloWorld"),是在beans.xml中配置过的,getBean后的名字必须要和beans.xml中定义的id名称一致,否则无法获取该HelloWorld bean的实例
  • 同时,我们发现,这里不再需要new了,我们只需要在一个称为IOC的容器中抓我们想要的对象即可,其实本质上来说,这不仅是一个框架的使用,更是一种编程思想的转变。没有使用Spring前,好比买菜要到菜市场,你得提个篮子去菜市场,可是有了Spring,我们轻松多了,把你的篮子甩到门口,自然就有人敲门送菜了。利用佟刚老师的话来说就是“传统的资源查找方式要求组件向容器发起请求查找资源. 作为回应, 容器适时的返回资源. 而应用了 IOC 之后, 则是容器主动地将资源推送给它所管理的组件, 组件所要做的仅是选择一种合适的方式来接受资源. 这种行为也被称为查找的被动形式”

依赖注入

  Spring IOC容器之所以能取到HelloWorld类,完全是基于依赖注入机制,骨子里就是反射机制,但是依赖注入的方式有多种,这里做一个简单介绍

 属性注入

  正如上面beans.xml中声明的那样,定义一个bean,id为helloWorld,class即类的全路径为com.jackie.spring.helloworld.HelloWorld

  使用<property>元素为bean注入值,name是bean的属性名称,这里正好也是name,value是bean属性对应的值,其实相当于调用了setName方法,将Jackie传给了HelloWorld的成员变量name。所以如果使用属性注入,需要在bean中定义好相应的set方法。

  构造器注入

  属性注入是通过set方法注入值,这里的构造器注入,显然是通过构造函数注入值的。举例来说:

  新建bean Car类

代码语言:javascript
复制
public class Car {

	private String company;
	private String brand;

	private int maxSpeed;
	private float price;

	public Car(String company, String brand, float price) {
		super();
		this.company = company;
		this.brand = brand;
		this.price = price;
	}

	public Car(String company, String brand, int maxSpeed) {
		super();
		this.company = company;
		this.brand = brand;
		this.maxSpeed = maxSpeed;
	}

	public Car(String company, String brand, int maxSpeed, float price) {
		super();
		this.company = company;
		this.brand = brand;
		this.maxSpeed = maxSpeed;
		this.price = price;
	}

	@Override
	public String toString() {
		return "Car [company=" + company + ", brand=" + brand + ", maxSpeed="
				+ maxSpeed + ", price=" + price + "]";
	}
}

  相应的,在beans.xml中定义如下

代码语言:javascript
复制
<bean id="car" class="com.jackie.spring.helloworld.Car">
	<constructor-arg value="DaZhong" index="1"></constructor-arg>
	<constructor-arg value="Shanghai" index="0"></constructor-arg>
	<constructor-arg value="250000" type="float"></constructor-arg>
</bean>

  这里是根据car类的构造函数来的,value对应构造函数中每个参数的具体值,对应顺序通过index来标示,但是如果car中有多个构造函数像上面的car类,这时候可以通过type参数指定参数的类型是什么,从而决定重载的是那个构造函数。

  在测试方法中加入

代码语言:javascript
复制
Car car = (Car) ctx.getBean("car");
System.out.println(car);

得到结果

Car [company=Shanghai, brand=DaZhong, maxSpeed=0, price=250000.0]

  同时这里简单介绍下如何在beans.xml中声明一个bean引用其他bean

  新建User类

代码语言:javascript
复制
public class User {

	private String userName;
	private List<Car> cars;
	
	private String wifeName;
	
	public String getWifeName() {
		return wifeName;
	}

	public void setWifeName(String wifeName) {
		System.out.println("setWifhName: " + wifeName);
		this.wifeName = wifeName;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public List<Car> getCars() {
		return cars;
	}

	public void setCars(List<Car> cars) {
		this.cars = cars;
	}
	
	public User() {
		System.out.println("User's Construtor...");
	}

	@Override
	public String toString() {
		return "User [userName=" + userName + ", cars=" + cars + "]";
	}
	
	public void init(){
		System.out.println("init method...");
	}
	
	public void destroy(){
		System.out.println("destroy method...");
	}

}

  在beans.xml中声明

代码语言:javascript
复制
<bean id="user" class="com.atguigu.spring.helloworld.User">
	<property name="userName" value="Jackie"></property>
	<property name="car" ref="car"></property>
</bean>

  测试类中加入

代码语言:javascript
复制
User user = (User) ctx.getBean("user");
System.out.println(user);

最终得到结果

User [userName=Jackie, cars=[Car [company=Shanghai, brand=DaZhong, maxSpeed=0, price=250000.0]]

注意:这里也可以使用内部bean的方式,而不需要通过ref属性指定其他bean

代码语言:javascript
复制
<bean id="user" class="com.atguigu.spring.helloworld.User">
	<property name="userName" value="Jack"></property>
	<property name="car">
             <bean class="com.jackie.spring.helloworld.Car">
			<constructor-arg value="DaZhong" index="1"></constructor-arg>
			<constructor-arg value="Shanghai" index="0"></constructor-arg>
			<constructor-arg value="250000" type="float"></constructor-arg>
            </bean>
        </property>
</bean>            

至此,我们了解了

  • Spring是什么
  • 如何创建一个Spring工程
  • 如何写基于Spring框架的HelloWorld
  • 两种依赖注入的方式属性注入和构造器注入
  • bean与bean之间的相互引用以及内部bean的概念

如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-11-20 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档