1. IOC
1.1 拓展
现代化的Java开发,就是基于Spring的开发
- SpringBoot
- 快速开发的脚手架
- 基于SpringBoot可以快速开发微服务
- 约定大于配置
- SpringCloud
- SpringCloud是基于SpringBoot实现的
学习SpringBoot的前提是掌握Spring以及SpringMVC,SpringBoot起到承上启下 的作用;
弊端:配置十分繁琐,人称:“配置地狱”;
1.2 IOC理论推导
问题展示
对象包:(接口)
package com.kangzhu.dao;
public interface UserDao {
public void getUser();
}
对象包:(实现1)
package com.kangzhu.dao;
public class UserDaoImpl implements UserDao{
@Override
public void getUser() {
System.out.println("I am the user");
}
}
对象包:(实现2)
package com.kangzhu.dao;
public class UserDaoMysqlImpl implements UserDao{
@Override
public void getUser() {
System.out.println("I am the user found by Mysql");
}
}
服务包:(接口)
package com.kangzhu.service;
public interface UserService {
public void getUser();
}
服务包:(实现)
package com.kangzhu.service;
import com.kangzhu.dao.UserDao;
import com.kangzhu.dao.UserDaoImpl;
import com.kangzhu.dao.UserDaoMysqlImpl;
public class UserServiceImpl implements UserService{
// private UserDao userDao = new UserDaoImpl();
private UserDao userDao = new UserDaoMysqlImpl();
@Override
public void getUser() {
// 业务层调用dao层
userDao.getUser();
}
}
客户端(测试类)
import com.kangzhu.service.UserServiceImpl;
public class MyTest {
public static void main(String[] args) {
// 用户实际调用的是业务层
UserServiceImpl userService = new UserServiceImpl();
userService.getUser();
}
}
问题在哪呢?
客户端的需求可能会影响我们的代码,如果说客户端想要通过普通的方式查询用户,服务包:(实现)中需要引入对象包(实现1),如果客户端想要通过Mysql的方式查询用户,需要引入对象包(实现2);
需要根据客户端的需求修改源代码,如果代码量很大,修改一次的成本就会十分昂贵!
解决方法(set注入)
改变服务实现类
package com.kangzhu.service;
import com.kangzhu.dao.UserDao;
public class UserServiceImpl implements UserService{
private UserDao userDao = null;
// set注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
客户端:
import com.kangzhu.dao.UserDaoMysqlImpl;
import com.kangzhu.service.UserServiceImpl;
public class MyTest {
public static void main(String[] args) {
// 用户实际调用的是业务层
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDao(new UserDaoMysqlImpl());
userService.getUser();
}
}
- 之前,程序是主动对象,控制权在程序员手上;
- 使用了set注入后,程序不再具有主动性,而是变成了接收对象;
这种思想从本质上解决了问题,程序员不用再去管理对象的创建;系统的耦合性降低,程序员可以专注在业务实现上;
这就是IOC的原型!
IOC的本质:
- 控制反转,是一种设计思想;
- 所谓控制反转就是:获得依赖对象的方式反转了;
2. HelloSpring
-
编写实体类
package com.kangzhu.pojo; public class Hello { private String str; public String getStr() { return str; } public void setStr(String str) { this.str = str; } @Override public String toString() { return "Hello{" + "str='" + str + '\'' + '}'; } }
-
添加配置文件(名称任意,这里是beans.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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--使用Spring来创建对象,在Spring这些都称为Bean 类型 变量名 = new 类型(); id = 变量名 class = new的对象 property 相当于给对象中的属性设置一个值 --> <bean id="hello" class="com.kangzhu.pojo.Hello"> <property name="str" value="Spring"/> </bean> </beans>
-
测试
import com.kangzhu.pojo.Hello; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { public static void main(String[] args) { // 获取Spring的上下文对象 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); // 我们的对象都在Spring中管理了,我们要使用,直接去里面取出来就可以了 Hello hello = (Hello) context.getBean("hello"); System.out.println(hello.toString()); } }
控制:传统应用程序对象是由程序控制创建的,使用Spring后,对象是由Spring来创建的;
反转:程序本身不创建对象,而变成被动的接收对象
3. IOC创建对象方式
-
使用无参构造创建对象,默认
-
使用有参构造创建对象
-
下标赋值
<bean id="user1" class="com.kangzhu.pojo.User"> <constructor-arg index="0" value="kangzhu1"/> </bean>
-
根据参数类型赋值
<!--但是假设有两个参数的类型相同,这种方式不适用--> <bean id="user2" class="com.kangzhu.pojo.User"> <constructor-arg type="java.lang.String" value="kangzhu2"/> </bean>
-
根据参数名赋值
<bean id="user3" class="com.kangzhu.pojo.User"> <constructor-arg name="name" value="kangzhu3"/> </bean>
-
4. Spring配置
4.1 别名
<alias name="user" alias="aliasUser"/>
这里的name是bean中的id,也就是对象名,alias是别名;
4.2 Bean的配置
id:bean的唯一标识符,也就是对象名;
class:bean对象所对应的权限命名(包名.类名);
name:也是别名,而且name更高级,可以同时取多个别名(不同别名间通过空格,逗号,分号等等进行分割);
4.3 import
import一般用于团队开发使用,它可以将多个配置文件导入合并为一个;
假设项目中有多个人开发,这三个人负责不同的类开发,不同的类需要注册在不同的bean中,我们可以利用import将所有人的beans.xml合并为一个总的;
- programmer1 --> beans1.xml
- programmer2 --> beans2.xml
- programmer3 --> beans3.xml
总的是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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<import resource="beans1.xml"/>
<import resource="beans2.xml"/>
<import resource="beans3.xml"/>
</beans>
如果说遇到相同的对象名,后面的会覆盖前面的;
5. 依赖注入
-
依赖:bean对象的创建依赖于容器;
-
注入:bean对象中的所有属性由容器注入;
5.1 构造器注入
上面的IOC创建对象方式中的使用有参构造创建对象就是构造器注入;
5.2 Set方式注入
这里创建两个实体类:
package com.kangzhu.pojo;
import java.util.*;
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbies;
private Map<String, String> card;
private Set<String> games;
private String wife;
private Properties info;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String[] getBooks() {
return books;
}
public void setBooks(String[] books) {
this.books = books;
}
public List<String> getHobbies() {
return hobbies;
}
public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
public Map<String, String> getCard() {
return card;
}
public void setCard(Map<String, String> card) {
this.card = card;
}
public Set<String> getGames() {
return games;
}
public void setGames(Set<String> games) {
this.games = games;
}
public String getWife() {
return wife;
}
public void setWife(String wife) {
this.wife = wife;
}
public Properties getInfo() {
return info;
}
public void setInfo(Properties info) {
this.info = info;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", address=" + address +
", books=" + Arrays.toString(books) +
", hobbies=" + hobbies +
", card=" + card +
", games=" + games +
", wife='" + wife + '\'' +
", info=" + info +
'}';
}
}
package com.kangzhu.pojo;
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
根据数据类型来看set注入:
<?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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="address" class="com.kangzhu.pojo.Address"/>
<bean id="student" class="com.kangzhu.pojo.Student">
<!-- 第一种,基本数据类型注入-->
<property name="name" value="kangzhu"/>
<!-- 第二种,引用注入-->
<property name="address" ref="address"/>
<!-- 第三种,数组注入-->
<property name="books">
<array>
<value>哈利波特</value>
<value>飘</value>
<value>箱子里的人</value>
</array>
</property>
<!-- 第四种,list注入-->
<property name="hobbies">
<list>
<value>电影</value>
<value>打游戏</value>
</list>
</property>
<!-- 第五种,map注入-->
<property name="card">
<map>
<entry key="学生卡" value="123456"/>
<entry key="身份证" value="123456"/>
</map>
</property>
<property name="games">
<set>
<value>LOL</value>
<value>COC</value>
<value>BOB</value>
</set>
</property>
<!-- 注入为null值-->
<property name="wife">
<null/>
</property>
<!-- properties注入-->
<property name="info">
<props>
<prop key="学号">123</prop>
<prop key="姓名">糠猪</prop>
</props>
</property>
</bean>
</beans>
5.3 拓展方式注入
可以使用p命名空间和c命名空间进行注入:
<?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"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- p命名空间注入,可以直接注入属性的值-->
<bean id="user" class="com.kangzhu.pojo.User" p:name="糠猪" p:age="18"/>
<!-- c命名空间注入-->
<bean id="user2" class="com.kangzhu.pojo.User" c:name="糠猪2" c:age="18"/>
</beans>
note:
-
p命名空间和c命名空间不能直接使用,需要导入xml约束:
xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c"
-
p代表properties,相当于set注入,c代表constructor,相当于构造器注入;