#spring(2)IOC/DI,构造器参数注入,按照名字,类自动注入,Spring基本值注入,利用Spring配置数据源, 集合注入,读取Properties文件,Spring 表达式,注解

本文详细介绍了Spring的依赖注入(DI)与控制反转(IOC)概念,包括构造器参数注入、按名称和类型自动注入、基本值注入等。此外,还展示了如何配置数据源、集合注入、读取Properties文件、使用Spring表达式以及各种注解的使用,如@Component、@Scope等,以实现对象生命周期的管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

## IOC/DI

DI 的优势:解耦

紧耦合:软件组件之间是紧密依赖,很难拆分

松耦合:软件组件之间是松散依赖,随时可以更换

解耦:将软件组件从紧耦合转换为松耦合关系。

### IOC、DI

利用Spring 管理光头强和工具之间的依赖关系

1. 创建工具接口

/**
		 * 工具接口 
		 */
		public interface Tool {
		
		}

2. 创建具体的工具 斧子

public class Axe implements Tool, Serializable {
			
			@Override
			public String toString() {
				return "斧子";
			}
		}

3. 创建锯

public class Saw implements Tool, Serializable{
			
			@Override
			public String toString() {
				return "电锯";
			}
		}

4. 创建工人类型

public class Worker implements Serializable {
			
			private String name; //基本值
			
			private Tool tool;   //Bean 对象
			
			private int age;     //基本值,
			
			
			public Worker() {
				name = "光头强";
			}
			
			public Worker(String name) {
				super();
				this.name = name;
			}
		
			public void setTool(Tool tool) {
				this.tool = tool;
				System.out.println("setTool:"+tool);
			}
			public Tool getTool() {
				return tool;
			}
			
			public String getName() {
				return name;
			}
		
			public void setName(String name) {
				this.name = name;
				System.out.println("setName:"+name);
			}
		
			public int getAge() {
				return age;
			}
		
			public void setAge(int age) {
				this.age = age;
				System.out.println("setAge:"+age);
			}
		
			public void work() { //测试方法
				System.out.println(name+"使用"+tool+"砍树"); 
			}
			@Override
			public String toString() {
				return "Worker [name=" + name + ", tool=" + tool + "]";
			}
		}

5. 在Spring配置文件中利用 IOC/DI 解决依赖关系

<!-- 控制反转 IOC:由Spring创建对象称为控制反转 -->
		<bean id="axe" class="day02.Axe"/>	
		<bean id="saw" class="day02.Saw"/>
		<bean id="qiang" class="day02.Worker">
			<!-- 依赖注入DI:由Spring帮助建立对象的依赖关系 -->
			<!-- spring会自动调用 setTool 方法注入 axe 引用 -->
			<property name="tool" ref="saw"/> 
		</bean>

6. 测试

public class TestCase {
		
			ClassPathXmlApplicationContext ctx;
			
			@Before
			public void init() {
				ctx=new ClassPathXmlApplicationContext(
						"applicationContext.xml");
			}
			
			@After
			public void destroy() {
				ctx.close();
			}
			
			@Test
			public void testQiang() {
				Worker qiang = ctx.getBean("qiang",Worker.class);
				qiang.work();
			}	
			
		}

### 构造器参数注入

Spring支持 利用 构造器创建对象:constructor-arg 子元素,其中index="0"用于指定参数在构造器参数的位置。

1. 配置

<bean id="xiong" class="day02.Worker" lazy-init="true">
			<!-- 构造器参数注入,也就是调用有参数
			构造器创建对象 -->
			<constructor-arg index="0" value="熊大"/>
			<property name="tool" ref="saw"/> 
		</bean>

2. 测试

@Test
		public void testXiong() {
			Worker xiong = ctx.getBean("xiong",Worker.class);
			xiong.work();
		}

### 按照名字自动注入

Spring支持自动按照名字注入功能,Spring会自动检查Bean属性和Bean ID的匹配,如果匹配上就自动完成注入

优点:自动注入可以减少XML文件的编写量。

1. 编写配置文件

<bean id="tool" class="day02.Axe" lazy-init="true"/>
		<!-- autowire="byName" 自动按照 Bean属性名字和id的
		名字 对应关系进行自动注入: bean属性叫tool匹配ID tool
		称为按照名字自动装配  autowire="byName"-->
		<bean id="tom" class="day02.Worker" 
			autowire="byName"/>

2. 测试

@Test
		public void testTom() {
			Worker tom= ctx.getBean("tom",Worker.class);
			tom.work();
		}

> 如果测试结果数 tool 属性不为空,则说明自动注入成功了

### 按照类型自动注入

为了实现按照类型注入,需要利于新的配置文件完成测试:

1. 编写 applicationContext1.xml

<!-- 测试  autowire="byType" 按照类型自动
		装配,解决对象的依赖关系 -->
		<bean class="day02.Axe"/>	
		<bean id="tom" class="day02.Worker" 
			autowire="byType"/>

2. 测试:

public class TestCase2 {
		
			ClassPathXmlApplicationContext ctx;
			@Before
			public void init() {
				ctx=new ClassPathXmlApplicationContext(
						"applicationContext2.xml");
			}
			@After
			public void destroy() {
				ctx.close();
			}
			@Test
			public void testTom() {
				Worker tom= ctx.getBean("tom",Worker.class);
				tom.work();
			}
		
		}

### Spring基本值注入

Spring支持为Bean注入基本类型参数, 这里的基本类型包括:8个基本类,8个包装类型,String类型。 

> Spring注入基本值时候也是调用的“Bean属性”方法实现的。

1. 配置 
 

<!-- 测试基本值的注入
		  基本值包含:8个基本类,8个包装类型,String类型 -->
		<bean id="andy" class="day02.Worker" lazy-init="true">
			<!-- 注入 JavaBean 对象,使用ref属性 -->
			<property name="tool" ref="axe"></property>
			<!-- 注解基本值,使用value属性 -->
			<property name="name" value="熊二"></property>
			<property name="age" value="10"></property>
		</bean>

2. Worker类

public class Worker implements Serializable {
			
			private String name; //基本值
			
			private Tool tool;   //Bean 对象
			
			private int age;     //基本值,
			
			private List<Tool> tools; //注入集合
			
			public Worker() {
				name = "光头强";
			}
			
			public Worker(String name) {
				super();
				this.name = name;
			}
		
			public void setTool(Tool tool) {
				this.tool = tool;
				System.out.println("setTool:"+tool);
			}
			public Tool getTool() {
				return tool;
			}
			
			public String getName() {
				return name;
			}
		
			public void setName(String name) {
				this.name = name;
				System.out.println("setName:"+name);
			}
		
			public int getAge() {
				return age;
			}
		
			public void setAge(int age) {
				this.age = age;
				System.out.println("setAge:"+age);
			}
		
			public List<Tool> getTools() {
				return tools;
			}
		
			public void setTools(List<Tool> tools) {
				this.tools = tools;
			}
		
			public void work() { //测试方法
				System.out.println(name+"使用"+tool+"砍树"); 
			}
			@Override
			public String toString() {
				return "Worker [name=" + name + ", tool=" + tool + "]";
			}
		}

3. 测试:

@Test
		public void testAndy() {
			Worker andy= ctx.getBean("andy",Worker.class);
			andy.work();
		}

### 案例:利用Spring配置数据源

1. 导入DBCP和MySQL驱动

<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>1.4</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.6</version>
		</dependency>		

2. 配置:

<!-- 利用Spring 创建 DataSource 连接池实例 -->
		<bean id="dataSource" 
			class="org.apache.commons.dbcp.BasicDataSource"
			destroy-method="close">
			<property name="driverClassName" 
				value="com.mysql.jdbc.Driver"/>
			<property name="url" 
				value="jdbc:mysql://localhost:3306/jsd1810db"/>
			<property name="username" value="root"/>
			<property name="password" value="root"/>
			<property name="maxActive" value="10"/>
			<property name="initialSize" value="2"/>
		</bean>	

3. 测试:

@Test
		public void testDataSource() 
			throws SQLException {
			//提示: BasicDataSource 实现了 DataSource接口
			//所以 使用 DataSource创建变量可以引用
			// BasicDataSource 对象实例
			DataSource ds = ctx.getBean("dataSource",
					DataSource.class);
			System.out.println(ds); 
			Connection conn = ds.getConnection();
			//执行SQL版本的Hello World
			String sql="select 'Hello World!' as str";
			Statement st=conn.createStatement();
			ResultSet rs=st.executeQuery(sql);
			while(rs.next()) {
				System.out.println(rs.getString("str"));
			}
			rs.close();
			st.close();
			conn.close();
		}

> 如果能够显示 Hello World 说明能够访问到数据库

### Spring 集合注入

当一个对象Bean属性是一个集合时候,可以利用Spring注入一个集合:

1. Worker类包含集合属性:

public class Worker implements Serializable {
			
			private String name; //基本值
			
			private Tool tool;   //Bean 对象
			
			private int age;     //基本值,
			
			private List<Tool> tools; //注入集合
			
			public Worker() {
				name = "光头强";
			}
			
			public Worker(String name) {
				super();
				this.name = name;
			}
		
			public void setTool(Tool tool) {
				this.tool = tool;
				System.out.println("setTool:"+tool);
			}
			public Tool getTool() {
				return tool;
			}
			
			public String getName() {
				return name;
			}
		
			public void setName(String name) {
				this.name = name;
				System.out.println("setName:"+name);
			}
		
			public int getAge() {
				return age;
			}
		
			public void setAge(int age) {
				this.age = age;
				System.out.println("setAge:"+age);
			}
		
			public List<Tool> getTools() {
				return tools;
			}
		
			public void setTools(List<Tool> tools) {
				this.tools = tools;
			}
		
			public void work() { //测试方法
				System.out.println(name+"使用"+tool+"砍树"); 
			}
			@Override
			public String toString() {
				return "Worker [name=" + name + ", tool=" + tool + "]";
			}
		}

2. 配置:

<!-- 为Bean对象注入集合 -->
		<bean id="john" class="day02.Worker">
			<!-- Bean对象注入 -->
			<property name="tool" ref="axe"></property>
			<!-- 基本值注入 -->
			<property name="name" value="大表哥"/>
			<!-- List集合注入 -->
			<property name="tools">
				<list>
					<bean class="day02.Saw"/>
					<bean class="day02.Axe"/>
					<bean class="day02.Saw"/>
				</list>
			</property>
		</bean>

3. 测试:

@Test
		public void testList() {
			Worker john = ctx.getBean("john", Worker.class);
			System.out.println(john.getTools()); 
		}

> 如果输出了集合的内容,不为空,则注入成功

### Spring读取Properties文件

Spring提供了读取Properties功能,Properties经常用于存储软件的参数:

1. 在resource文件夹中编写配置文件 jdbc.properties

driver=com.mysql.jdbc.Driver
		url=jdbc:mysql://localhost:3306/jsd1810db?useUnicode=true&characterEncoding=UTF-8
		username=root
		password=root
		initSize=3
		maxSize=5

2. 配置 

<!-- 利用Spring读取Properties文件 
		location: 位置,定位,这里是文件位置 -->
		<util:properties id="jdbc" 
		 	location="classpath:jdbc.properties"/>

3. 测试:

@Test
		public void testProperties() {
			Properties cfg=ctx.getBean("jdbc",
					Properties.class);
			System.out.println(cfg); 
		}

### Spring 表达式

Spring表达式的语法与EL表达式类似:

1. EL表达式: ${}  Spring表达式: #{}
2. Spring表达式也可以读取
    - Bean属性: #{qiang.name}  #{qiang['name']}
    - 数组元素: #{arr[0]}
    - List元素: #{list[1]}
    - Map(Properties)元素: #{jdbc.username} #{jdbc['username']} 
3. 在Spring文件中,可以利用Spring表达式,将一个Bean对象的属性,赋值给另外一个Bean。 

使用Spring 表达式配置数据源:

1. 配置:

<!-- 利用Spring读取Properties文件 
		location: 位置,定位,这里是文件位置 -->
		<util:properties id="jdbc" 
		 	location="classpath:jdbc.properties"/>
		
		<bean id="ds" class="org.apache.commons.dbcp.BasicDataSource">
			<!-- 读取 jdbc的driver属性,将值赋值给
			 driverClassName 属性-->
			<property name="driverClassName"
				value="#{jdbc.driver}"/>
			<property name="url" 
				value="#{jdbc.url}"/>
			<property name="username"
				value="#{jdbc.username}"/>
			<property name="password"
				value="#{jdbc.password}"/>
			<property name="initialSize"
				value="#{jdbc.initSize}"/>
			<property name="maxActive"
				value="#{jdbc.maxSize}"/>
		</bean> 

2. 测试:


		@Test
		public void testDS() 
			throws SQLException {
			//提示: BasicDataSource 实现了 DataSource接口
			//所以 使用 DataSource创建变量可以引用
			// BasicDataSource 对象实例
			DataSource ds = ctx.getBean("ds",
					DataSource.class);
			System.out.println(ds); 
			Connection conn = ds.getConnection();
			//执行SQL版本的Hello World
			String sql="select 'Hello World2!' as str";
			Statement st=conn.createStatement();
			ResultSet rs=st.executeQuery(sql);
			while(rs.next()) {
				System.out.println(rs.getString("str"));
			}
			rs.close();
			st.close();
			conn.close();
		}
 

## Spring 注解

Spring 提供了一系列注解,用于管理JavaBean。

1. 注解是Java语法,被Java编译器检查,可以减少配置错误
2. 注解提供了默认支持功能,默认情况下会自动完成注入功能
3. 注解和XML配置可以混合使用。
    1. 自己写的类使用注解
    2. 别人写的API使用XML配置

### 利用Spring注解创建Bean

1. 创建Java类,标注注解

package day02.bean;

		@Component //默认的BeanID为 "demoBean"
		public class DemoBean implements Serializable{
			
			@Override
			public String toString() {
				return "DemoBean";
			}
		}

> Spring 会自动查找注解@Componment 找到后自动实例 DemoBean 并且自动分配Bean的ID: demoBean
    
2. 需要在XML配置文件中开启注解扫描功能。

<context:component-scan base-package="day02.bean"/>

> base-package="day02.bean" 指定Spring扫描组件的包范围

3. 测试:

@Test
		public void testDemoBean() {
			DemoBean bean = ctx.getBean("demoBean",
					DemoBean.class);
			System.out.println(bean); 
		}

### Spring 支持多个组件注解

这些注解功能是一样的,建议按照组件层次使用组件组件。  

@Component   通用组件 
@Named       通用组件 
@Repository  持久层组件
@Service     业务层组件
@Controller  控制器

> 其中@Named来自 javax.inject 包,需要利用Maven导入

案例:

1. 声明类


		@Repository // BeanID 是 demoBean2
		public class DemoBean2 {
			
			@Override
			public String toString() {
				return "DemoBean2";
			}
		}

2. 测试

@Test
		public void testDemoBean2() {
			DemoBean2 bean = ctx.getBean("demoBean2",
					DemoBean2.class);
			System.out.println(bean); 
		}

### 自定义BeanID

如果需要修改默认的BeanID,可以指定BeanID

1. 声明类

@Component("myBean") //自定义BeanID为 myBean
		public class TestBean implements Serializable{
			
			@Override
			public String toString() {
				return "testBean";
			}
		}

2. 测试

@Test
		public void testMyBean() {
			TestBean bean = ctx.getBean("myBean",
					TestBean.class);
			System.out.println(bean); 
		}

### @Scope 创建多个实例

声明类:

@Component
	@Scope("prototype") //创建多个对象实例
	public class DemoBean3 {
		
	}

测试:

@Test
	public void testDemoBean3() {
		DemoBean3 bean1 = ctx.getBean("demoBean3",
				DemoBean3.class);
		DemoBean3 bean2 = ctx.getBean("demoBean3",
				DemoBean3.class);
		System.out.println(bean1==bean2);
		 
	}

### 管理对象的声明周期

@PostConstruct 构造器之后执行方法
@PreDestroy 在销毁之前执行的方法

1. 导入注解包

<dependency>
			<groupId>javax.annotation</groupId>
			<artifactId>javax.annotation-api</artifactId>
			<version>1.3.2</version>
		</dependency>

		<dependency>
			<groupId>javax.inject</groupId>
			<artifactId>javax.inject</artifactId>
			<version>1</version>
		</dependency>

2. 编写类:


		@Named
		public class Writer implements Serializable{
			
			private PrintWriter out;
			
			//Post 在..以后,Construct:构造器
			@PostConstruct //在构造器以后执行 init方法
			public void init() throws Exception {
				out = new PrintWriter("demo.txt");
				System.out.println("init()");
			}
			public void write(String str) {
				out.println(str);
			}
			
			//Pre 前, Destroy 销毁
			@PreDestroy //在销毁之前执行close()
			public void close() {
				out.flush();
				out.close();
				System.out.println("close()");
			}
		}

3. 测试

@Test
		public void testInitDestroy() {
			Writer writer = ctx.getBean("writer",
					Writer.class);
			writer.write("Hello World!"); 
		}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值