目录
分层解耦
三层架构
controller:控制层,接收前端发送的请求,对请求进行处理,并响应数据
service:业务逻辑层,处理具体的业务逻辑
dao:数据访问层(Data Access Object)(持久层),负责数据访问操作,包括数据地址增,删,改,查
分层解耦
内聚:软件中各个功能模块内部的功能联系
耦合:衡量软件中各个层/模块之间的依赖,关联程度
软件设计原则:高内聚低耦合
控制反转:对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转
依赖注入:容器为应用程序提供运行时,所依赖的资源,称为依赖注入
Bean对象:IOC容器创建、管理的对象,称之为bean
IoC控制反转
由service或者dao使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转
Spring技术对Ioc思想进行了实现
Spring提供了一个容器称作IoC容器,用来充当IoC思想中的外部
IoC容器负责对象的创建,初始化等一系列工作,被创建或 被管理的对象在IoC容器中统称为Bean
目标是充分解耦
最终目标是使用对象时不仅可以直接从IoC容器中获取,并且获取到Bean已经绑定了所有的依赖关系
bean的声明
要把某个对象交给IOC容器管理,需要在对应的类上加如下注解之一:
@Component表示将当前类交给IOC容器管理,成为IOC容器中的bean
声明bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写
使用以上四个注解都可以声明bean,但在springboot集成web开发中,声明控制器bean只能用@controller
bean组件扫描
前面声明bean的四大注解,要想生效,还需要被组件扫描注解@ComponsentScan扫描
@ComponentScan注解虽然没有显示配置,但是实际上已经包含在了启动类声明注解@SpringBootApplication中,默认扫描范围是启动类所包含在包及其子包
案例
1.导入spring坐标
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.8</version>
</dependency>
</dependencies>
2,定义spring管理的类(接口)
public interface BookService {
public void save();
}
public class BookServiceImpl implements BookService {
private BookDao bookDao=new BookDaoImpl();
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
//6.提供对应的set方法
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
3.创建spring配置文件,配置对应类作为spring管理的bean
<?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">
<!--在pom中导入spring坐标,版本是5点多-->
<!--<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.8</version>-->
<!--配置bean-->
<!--bean标签表示配置bean
id属性表示给bean起名字
class属性表示给bean定义类型-->
<bean id="bookDao" class="org.example.impl.BookDaoImpl"/>
<bean id="bookService" class="org.example.service.impl.BookServiceImpl"/>
</beans>
bean定义时id属性在同一个上下文中不能重复
4.初始化IoC容器(Spring核心容器/Spring容器),通过容器获取bean
public class App2 {
public static void main(String[] args) {
//获取IoC容器
ApplicationContext ctx=new ClassPathXmlApplicationContext("ApplicationContext.xml");
//获取bean对象
BookDao bookDao=(BookDao)ctx.getBean("bookDao");
bookDao.save();
BookService bc = (BookService) ctx.getBean("bookService");
bc.save(); //book dao save ...
//book service save ...
//book dao save ...
}
}
(加上DI以后的使用)
5.删除使用new的形式创建对象的代码,提供依赖对象对应的setter方法
public class BookServiceImpl implements BookService {
//5.删除业务层中使用new的方式创建的dao对象
private BookDao bookDao;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
//6.提供对应的set方法
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
6.配置service和dao之间的关系
<bean id="bookDao" class="org.example.impl.BookDaoImpl"/>
<bean id="bookService" class="org.example.service.impl.BookServiceImpl">
<!--配置server和dao的关系
prooerty标签表示配置当前bean属性
name属性表示配置哪一个具体的属性
ref属性表示参照哪一个bean-->
<property name="bookDao" ref="bookDao"/>
</bean>
</beans>
DI依赖注入
setter注入
引用类型
即案例中的5,配置中使用property标签ref属性注入引用类型对象
简单类型
在bean中定义引用类型属性并提供可访问的set方法
public class BookDaoImpl implements BookDao {
private int connectionNumber;
public void setConnectionNumber(int connectionNumber) {
this.connectionNumber = connectionNumber;
}
}
配置中使用property标签value属性注入简单类型数据
<bean id="bookDao" class="org.example.impl.BookDaoImpl" >
<property name="connectionNumber" value="100"/>
</bean>
构造器注入
引用类型
在bean中定义引用类型属性并提供可访问的构造方法
public class BookServiceImpl implements BookService {
private BookDao bookDao;
private UserDao userDao;
public BookServiceImpl(BookDao bookDao, UserDao userDao) {
this.bookDao = bookDao;
this.userDao = userDao;
}
}
配置中使用constructor-args标签ref属性注入引用类型的对象
<bean id="bookService" class="org.example.service.impl.BookServiceImpl">
<constructor-arg name="bookDao" ref="bookDao"/>
</bean>
<bean id="bookDao" class="org.example.dao.impl.BookDaoImpl"/>
简单类型
在bean中定义引用类型属性并提供可访问的set方法
public class BookDaoImpl {
private String databaseName;
private int connectionNum;
public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
public void setConnectionNum(int connectionNum) {
this.connectionNum = connectionNum;
}
}
配置中使用constructor-arg标签value属性注入简单类型数据
<bean id="bookDao" class="org.example.dao.impl.BookDaoImpl">
<constructor-arg name="connectionNumber" value="10"/>
</bean>
<!--
标准书写 这个存在的问题是如果前面的名称修改了,这个也得一直修改
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
根据构造方法参数名称注入
<constructor-arg name="connectionNum" value="10"/>
<constructor-arg name="databaseName" value="mysql"/>
</bean>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<constructor-arg name="userDao" ref="userDao"/>
<constructor-arg name="bookDao" ref="bookDao"/>
</bean>
-->
<!--
解决形参名称的问题,与形参名不耦合 这个的问题是如果两个的类型一样,又无法区分了
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
根据构造方法参数类型注入
<constructor-arg type="int" value="10"/>
<constructor-arg type="java.lang.String" value="mysql"/>
</bean>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<constructor-arg name="userDao" ref="userDao"/>
<constructor-arg name="bookDao" ref="bookDao"/>
</bean> -->
<!-- 解决参数类型重复问题,使用位置解决参数匹配 -->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<!-- 根据构造方法参数位置注入 -->
<constructor-arg index="0" value="mysql"/>
<constructor-arg index="1" value="100"/>
</bean>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<constructor-arg name="userDao" ref="userDao"/>
<constructor-arg name="bookDao" ref="bookDao"/>
</bean>
方式选择
强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
可选依赖使用setter注入进行,灵活性强
Spring框架倡导使用构造器,第三框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
如果有必要可以两者同时使用,使用构造器注入完成强制依赖注入,使用setter注入完成可选依赖的注入
实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
自己开发的模块推荐使用setter注入
依赖自动装配
IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配,其方式有四种,分别是按类型按名称构造器(不推荐)还有一个没有
<bean id="bookDao" class="org.example.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="org.example.service.impl.BookServiceImpl" autowire="byType"/>
注意:
自动装配用于引用类型依赖注入,不能对简单类型进行操作
使用时按照类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
使用时按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用(就是前面改了名称我后面配置那里没改自动配置就会报错)
自动装配优先级低于setter注入和构造器注入,同时出现时自动装配配置失效
集合注入
注入对象
<bean id="bookDao" class="org.example.dao.impl.BookDaoImpl">
<property name="array">
<array>
<value>100</value>
<value>200</value>
<value>300</value>
</array>
</property>
<property name="list">
<list>
<value>xixi</value>
<value>haha</value>
<value>zz</value>
</list>
</property>
<property name="set">
<set>
<value>huhu</value>
<value>hiha</value>
<value>zza</value>
</set>
</property>
<property name="map">
<map>
<entry key="aa" value="xx"/>
<entry key="cc" value="ee"/>
<entry key="ff" value="gg"/>
</map>
</property>
<property name="properties">
<props>
<prop key="aa">xx</prop>
<prop key="cc">ee</prop>
<prop key="ff">gg</prop>
</props>
</property>
</bean>
</beans>
public class AppForSiCollection {
public static void main(String[] args) {
ApplicationContext ctx=new ClassPathXmlApplicationContext("ApplicationContext.xml");
BookDao bookDao=(BookDao) ctx.getBean("bookDao");
bookDao.save();//book dao saving。。。 遍历数组[100, 200, 300] 遍历list[xixi, haha, zz] 遍历set[huhu, hiha, zza] 遍历map{aa=xx, cc=ee, ff=gg} 遍历properties{aa=xx, cc=ee, ff=gg}
}
}
在Spring框架
不用管那么多坐标引入了
@Autowired注解(运行时,IOC容器会提供该类型的bean对象,并且赋值给该变量--依赖注入),默认是按照类型进行,如果存在多个相同类型的bean,将会报错,可以通过
@Primary(用来设置bean的优先级,想让谁生效就在她的class上面再添加上这个注解)
@Primary
@Service
public class EmployeeServiceB inmplments EmployService{}//表示的是我要执行这个。
@Qualifier(配合@Autowired直接指定要注入哪个bean)(默认按照类型注入)
@RestController
publicclassEmpController{
@Autowired
@Qualifier("empServiceA")//引号里面的是类名首字母小写@Qualifier("bean的名称)
private EmpService empService;
}
@Resource(默认按照名称注入)
在容器中建立Bean与Bean之间的依赖关系的整个过程,成为依赖注入,注入有两种方法
@RestController
public class EmpController{
@Resource(name="empServiceB")//name="bean的名称"
private EmpService empService;
}
@Resource和@Autowired
他们的区别在于:
@Autowired是Spring框架提供的注解,而@Resource是JDK提供的注解
@Resource默认是按照类型注入 ,而@Resource默认按照名称注入