Spring IOC 注入
主动实例化
1.设置配置文件
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="accountService" class="com.xxxx.service.AccountService"/>
</beans>
2.编写Bean对象
AccountDao.java
package com.xxxx.dao;
public class AccountDao {
public void test(){
System.out.println("AccountDao...");
}
}
AccountService.java
package com.xxxx.service;
import com.xxxx.dao.AccountDao;
public class AccountService {
//主动实例化
AccountDao accountDao = new AccountDao();
public void test(){
System.out.println("AccountService...");
accountDao.test();
}
}
3.获取实例化对象
package com.xxxx;
import com.xxxx.service.AccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
AccountService accountService = (AccountService) ac.getBean("accountService");
accountService.test();
}
}
4.运行结果
AccountService...
AccountDao...
Spring IOC 手动注入(装配)
set方法注入
属性字段需要提供set⽅法
业务对象 JavaBean
1.dao层的bean对象
package com.xxxx.dao;
public class AccountDao {
public void test(){
System.out.println("AccountDao...");
}
}
2.属性字段提供set方法
package com.xxxx.service;
import com.xxxx.dao.AccountDao;
public class AccountService {
//JavaBean对象 手动注入 set方法注入
private AccountDao accountDao;
//提供set方法
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public void test(){
System.out.println("AccountService...");
accountDao.test();
}
}
3.配置文件的bean标签设置property标签
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--set方法注入,需要提供set方法-->
<!--通过property属性设置set方法-->
<!--name:字段名 ref:对应的bean标签的is属性值-->
<bean id="accountDao" class="com.xxxx.dao.AccountDao"/>
<bean id="accountService" class="com.xxxx.service.AccountService">
<!--set方法注入:JavaBean对象-->
<property name="accountDao" ref="accountDao"/>
</bean>
</beans>
4.获取实例化对象
package com.xxxx;
import com.xxxx.service.AccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
AccountService accountService = (AccountService) ac.getBean("accountService");
accountService.test();
}
}
5.运行结果
AccountService...
AccountDao...
常用对象和基本类型
1.属性字段提供set方法
package com.xxxx.service;
public class AccountService {
//字符串类型
private String host;
//提供set方法
public void setHost(String host) {
this.host = host;
}
//基本类型
private Integer port;
//提供set方法
public void setPort(Integer port) {
this.port = port;
}
public void test(){
System.out.println("AccountService...");
System.out.println(host);
System.out.println(port);
}
}
2.配置文件的bean标签设置property标签
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--set方法注入,需要提供set方法-->
<!--通过property属性设置set方法-->
<!--name:bean对象中属性字段名 value:具体的值(基本类型、常用对象|日期 集合)-->
<bean id="accountService" class="com.xxxx.service.AccountService">
<!--字符串类型-->
<property name="host" value="localhost"/>
<!--基本类型-->
<property name="port" value="8080"/>
</bean>
</beans>
3.获取实例化对象
package com.xxxx;
import com.xxxx.service.AccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
AccountService accountService = (AccountService) ac.getBean("accountService");
accountService.test();
}
}
4.运行结果
AccountService...
localhost
8080
集合类型和属性对象
1.属性字段提供set方法
package com.xxxx.service;
import com.xxxx.dao.AccountDao;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class AccountService {
//List集合
private List<String> list;
public void setList(List<String> list) {
this.list = list;
}
//list集合输出
public void printList(){
list.forEach(v -> System.out.println(v));
}
//Set集合
private Set<String> set;
public void setSet(Set<String> set) {
this.set = set;
}
// Set集合输出
public void printSet() {
set.forEach(s -> System.out.println(s));
}
//Map
private Map<String,Object> map;
public void setMap(Map<String, Object> map) {
this.map = map;
}
// Map输出
public void printMap() {
map.forEach((k,v) -> System.out.println(k + "," + v));
}
//Properties
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
// Properties输出
public void printProperties(){
properties.forEach((k,v) -> System.out.println(k + ","+ v ));
}
public void test(){
System.out.println("AccountService...");
// List集合
printList();
// Set集合
printSet();
// Map
printMap();
// Properties
printProperties();
}
}
2.配置文件的bean标签设置property标签
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--set方法注入,需要提供set方法-->
<!--通过property属性设置set方法-->
<!--name:bean对象中属性字段名 value:具体的值(基本类型、常用对象|日期 集合)-->
<bean id="accountService" class="com.xxxx.service.AccountService">
<!--List集合注入-->
<property name="list">
<list>
<value>北京</value>
<value>上海</value>
<value>深圳</value>
</list>
</property>
<!--Set集合注⼊-->
<property name="set">
<set>
<value>上海SH</value>
<value>北京BJ</value>
<value>杭州HZ</value>
</set>
</property>
<!--Map注⼊-->
<property name="map">
<map>
<entry>
<key><value>周杰伦</value></key>
<value>我是如此相信</value>
</entry>
<entry>
<key><value>林俊杰</value></key>
<value>可惜没如果</value>
</entry>
<entry>
<key><value>陈奕迅</value></key>
<value>⼗年</value>
</entry>
</map>
</property>
<!--Properties注⼊-->
<property name="properties">
<props>
<prop key="上海">东⽅明珠</prop>
<prop key="北京">天安⻔</prop>
<prop key="杭州">⻄湖</prop>
</props>
</property>
</bean>
</beans>
3.获取实例化对象
package com.xxxx;
import com.xxxx.service.AccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
AccountService accountService = (AccountService) ac.getBean("accountService");
accountService.test();
}
}
4.运行结果
AccountService...
北京
上海
深圳
上海SH
北京BJ
杭州HZ
周杰伦,我是如此相信
林俊杰,可惜没如果
陈奕迅,⼗年
上海,东⽅明珠
北京,天安⻔
杭州,⻄湖
构造器注入
需要提供带参构造器,构造器有几个参数就需要设置几个constructor-arg标签
通过constructor-arg标签设置构造器的形参(name 形参名 )
单个Bean对象作为参数
1.JavaBean对象
package com.xxxx.service;
import com.xxxx.dao.TypeDao;
/**
* 构造器注入
*/
public class TypeService {
private TypeDao typeDao;
//提供带参构造
public TypeService(TypeDao typeDao) {
this.typeDao = typeDao;
}
public void test(){
System.out.println("TypeService...");
typeDao.test();
}
}
2.设置配置文件
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--构造器注入-->
<bean id="typeDao" class="com.xxxx.dao.TypeDao"/>
<bean id="typeService" class="com.xxxx.service.TypeService">
<constructor-arg name="typeDao" ref="typeDao"/>
</bean>
</beans>
3.获取实例化对象
package com.xxxx;
import com.xxxx.service.TypeService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
TypeService typeService = (TypeService) ac.getBean("typeService");
typeService.test();
}
}
4.运行结果
TypeService...
TypeDao...
多个Bean对象作为参数
1.JavaBean对象
package com.xxxx.service;
import com.xxxx.dao.TypeDao;
import com.xxxx.dao.UserDao;
/**
* 构造器注入
*/
public class TypeService {
private TypeDao typeDao;
private UserDao userDao;
//提供带参构造
public TypeService(TypeDao typeDao, UserDao userDao) {
this.typeDao = typeDao;
this.userDao = userDao;
}
public void test(){
System.out.println("TypeService...");
typeDao.test();
userDao.test();
}
}
2.设置配置文件
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--构造器注入-->
<bean id="typeDao" class="com.xxxx.dao.TypeDao"/>
<bean id="userDao" class="com.xxxx.dao.UserDao"/>
<bean id="typeService" class="com.xxxx.service.TypeService">
<constructor-arg name="typeDao" ref="typeDao"/>
<constructor-arg name="userDao" ref="userDao"/>
</bean>
</beans>
3.获取实例化对象
package com.xxxx;
import com.xxxx.service.TypeService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
TypeService typeService = (TypeService) ac.getBean("typeService");
typeService.test();
}
}
4.运行结果
TypeService...
TypeDao...
UserDao...
Bean对象和常用对象作为参数
package com.xxxx.service;
import com.xxxx.dao.TypeDao;
import com.xxxx.dao.UserDao;
/**
* 构造器注入
*/
public class TypeService {
private TypeDao typeDao;
private UserDao userDao;
private String name;
public TypeService(TypeDao typeDao, UserDao userDao, String name) {
this.typeDao = typeDao;
this.userDao = userDao;
this.name = name;
}
public void test(){
System.out.println("TypeService...");
typeDao.test();
userDao.test();
System.out.println(name);
}
}
设置配置文件
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--构造器注入-->
<bean id="typeDao" class="com.xxxx.dao.TypeDao"/>
<bean id="userDao" class="com.xxxx.dao.UserDao"/>
<bean id="typeService" class="com.xxxx.service.TypeService">
<constructor-arg name="typeDao" ref="typeDao"/>
<constructor-arg name="userDao" ref="userDao" />
<constructor-arg name="name" value="admin" index="2"/>
<!--index:构造器中参数的下标,从0开始-->
</bean>
</beans>
获取实例化对象
package com.xxxx;
import com.xxxx.service.TypeService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
TypeService typeService = (TypeService) ac.getBean("typeService");
typeService.test();
}
}
运行结果
TypeService...
TypeDao...
UserDao...
admin
循环依赖问题
循环问题产生的原因:
Bean通过构造器注入,之间彼此相互依赖对方导致bean无法实例化。
问题展示:
A.java
package com.xxxx.service;
import com.xxxx.dao.B;
public class A {
private B b;
public A(B b) {
this.b = b;
}
public void test(){
System.out.println("A test ...");
b.test();
}
}
B.java
package com.xxxx.dao;
import com.xxxx.service.A;
public class B {
private A a;
public B(A a) {
this.a = a;
}
public void test(){
System.out.println("B test ...");
a.test();
}
}
设置配置文件
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="a" class="com.xxxx.service.A">
<constructor-arg name="b" ref="b"/>
</bean>
<bean id="b" class="com.xxxx.dao.B">
<constructor-arg name="a" ref="a"/>
</bean>
</beans>
测试
package com.xxxx;
import com.xxxx.service.TypeService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
}
}
解决循环依赖
如何解决:将构造器注入改为set方法注入
1.将构造方法换成set方法
package com.xxxx.service;
import com.xxxx.dao.B;
public class A {
private B b;
// public A(B b) {
// this.b = b;
// }
public void setB(B b) {
this.b = b;
}
public void test(){
System.out.println("A test ...");
b.test();
}
}
package com.xxxx.dao;
import com.xxxx.service.A;
public class B {
private A a;
// public B(A a) {
// this.a = a;
// }
public void setA(A a) {
this.a = a;
}
public void test(){
System.out.println("B test ...");
a.test();
}
}
2.修改标签
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- <bean id="a" class="com.xxxx.service.A">-->
<!-- <constructor-arg name="b" ref="b"/>-->
<!-- </bean>-->
<!-- <bean id="b" class="com.xxxx.dao.B">-->
<!-- <constructor-arg name="a" ref="a"/>-->
<!-- </bean>-->
<bean id="a" class="com.xxxx.service.A">
<property name="b" ref="b"/>
</bean>
<bean id="b" class="com.xxxx.dao.B">
<property name="a" ref="a"/>
</bean>
</beans>
静态工厂注入
1.定义静态工厂类
package com.xxxx.factory;
import com.xxxx.dao.UserDao;
/**
* 静态工厂类
* 1.定义静态工厂类
* 2.定义静态方法,并返回需要被实例化的Bean对象
*/
public class StaticFactory {
/**
* 静态方法
*/
public static UserDao createUserDao(){
System.out.println("静态工厂实例化...");
return new UserDao();
}
}
2.java代码
package com.xxxx.service;
import com.xxxx.dao.UserDao;
public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void test(){
System.out.println("UserService...");
}
}
xml配置
<bean id="userService" class="com.xxxx.service.UserService">
<property name="userDao" ref="userDao"/>
</bean>
<bean id="userDao" class="com.xxxx.factory.StaticFactory" factory-method="createUserDao"/>
实例化工厂注入
1.定义工厂类
package com.xxxx.factory;
import com.xxxx.dao.UserDao;
public class InstanceFactory {
/**
* 定义方法,返回实例化对象
*/
public UserDao createUserDao(){
System.out.println("实例化工厂实例化...");
return new UserDao();
}
}
2.java代码
package com.xxxx.service;
import com.xxxx.dao.UserDao;
public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void test(){
System.out.println("UserService...");
}
}
3.xml配置
<bean id="userService" class="com.xxxx.service.UserService">
<property name="userDao" ref="userDao"/>
</bean>
<!--实例化工厂注入:也是借助set方法注入,只是被注入的bean对象的实力护士是通过工厂实例化的-->
<bean id="instanceFactory" class="com.xxxx.factory.InstanceFactory"/>
<bean id="userDao" factory-bean="instanceFactory" factory-method="createUserDao"/>
注入方式的选择
开发项目中set方式注入首选
使⽤构造注入可以在构建对象的同时⼀并完成依赖关系的建⽴,对象⼀建⽴则所有的⼀切也就准备好了,但如果要建⽴的对象关系很多,
使⽤构造器注⼊会在构建函数上留下⼀⻓串的参数,且不易记忆,这时使⽤Set注⼊会是个不错的选择。
使⽤Set注⼊可以有明确的名称,可以了解注⼊的对象会是什么,像setXXX()这样的名称会⽐记忆Constructor上某个参数的位置代表某个对象更好。
p名称空间的使用
spring2.5以后,为了简化setter方法属性注入,引用p名称空间的概念,可以将 property 子元素简化为 bean 元素属性配置。
1.属性字段提供 set 方法
public class UserService {
// 业务对象UserDao set注⼊(提供set⽅法)
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
// 常⽤对象String set注⼊(提供set⽅法)
private String host;
public void setHost(String host) {
this.host = host;
}
}
2.在配置文件spring.xml引入p名称空间
xmlns:p="http://www.springframework.org/schema/p"
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="com.xxxx.dao.UserDao"></bean>
<!--
p:属性名:="xxx" 引⼊常量值
p:属性名-ref:="xxx" 引⼊其他Bean对象的id属性值
-->
<bean id="userService" class="com.xxxx.service.UserService"
p:userDao-ref="userDao"
p:host="127.0.0.1" />
</beans>