Spring
Spring Framework系统架构
学习顺序:
- Core Container核心容器
- AOP
- Data Integration 数据继承
- Data Access 数据访问
Spring 核心概念
目前代码存在的问题:代码耦合度强
1.IoC(Inversion of Control)控制反转
使用对象时,由主动new产生对象(强耦合)转换为由“外部(Spring)”提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转。
Spring提供一个容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为“Bean”
2.DI(Dependency Injection)依赖注入
在IoC容器内将有依赖关系的bean进行关系绑定
IoC案例
1.数据准备
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
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();
}
}
2.导入Spring坐标,刷新Maven
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
3.新建Spring配置文件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">
<!--
bean标签:表示配置bean
id属性:表示给bean起名字
class属性:表示给bean定义类型
-->
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"></bean>
</beans>
4.初始化IoC容器,通过容器获取Bean对象
public class test2 {
public static void main(String[] args) {
//1.创建IoC容器对象,加载spring核心配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2 从IOC容器中获取Bean对象(BookService对象)
BookService bookService= (BookService)ctx.getBean("bookService");
//3 调用Bean对象(BookService对象)的方法
bookService.save();
}
}
DI案例
DI核心思想是依赖注入,即两个有关联得Bean进行关系绑定,再次进行解耦合。
1.删除Service中使用new创建的Dao对象
private BookDao bookDao = new BookDaoImpl();
public class BookServiceImpl implements BookService {
private BookDao bookDao;
@Override
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
2.生成依赖对象的setter方法
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
3.在applicationContext.xml中配置
<bean id="BookDao" class="Dao.impl.BookDaoImpl"/>
<!-- 配置server与dao的关系-->
<!-- property标签:表示配置当前bean的属性-->
<!-- name属性:表示配置哪一个具体的属性-->
<!-- ref属性:表示参照哪一个bean-->
<bean id="BookService" class="Service.impl.BookServiceImpl">
<property name="bookDao" ref="BookDao"/>
</bean>
参数对应关系图解:
Bean基础配置
Bean作用范围
配置说明
类别 | 描述 |
---|---|
名称 | scope |
功能 | 定义Bean作用域 1.singleton(单例)默认 2.prototype(原型、非单例) |
范例 | <bean id="BookDao"class="Dao.impl.BookDaoImpl" scope="prototype"/> |
交给容器进行管理的Bean包括:表现层对象(Servlet, Controller)、业务层(Service)对象、数据层(Dao)对象、工具(Util)对象
扩展:常见项目的包命名结构
com.xxx.yyy.dao dao层接口 com.xxx.yyy.dao.impl dao层实现 com.xxx.yyy.service service层接口 com.xxx.yyy.service.impl service层实现 com.xxx.yyy.web web层 com.xxx.yyy.util 工具包 com.xxx.yyy.domain javabean
另:scope的取值不仅仅只有singleton和prototype,还有request、session、 globalSession
Bean实例化的三种形式
1.构造方法
public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
System.out.println("book dao constructor is running ....");
}
public void save() {
System.out.println("book dao save ...");
}
}
将构造方法的public访问权限改为private后仍然可以执行输出语句,因为底层采用Java反射的原理
注意:无参构造方法如果不存在,将抛出异常
BeanCreationException
2.静态工厂(兼容旧版代码)
创建OrderDao接口、OrderDaoImpl实现类和OrderDaoFatory工厂类
public interface OrderDao {
public void save();
}
public class OrderDaoImpl implements OrderDao {
public void save() {
System.out.println("order dao save ...");
}
}
//静态工厂类
public class OrderDaoFactory {
public static OrderDao getOrderDao(){
System.out.println("factory setup....");
return new OrderDaoImpl();
}
}
配置applicationContext.xml
<bean id="orderDao" class="Factory.OrderDaoFactory" factory-method="getOrderDao"/>
3.实现FactoryBean<T>方式
定义UserDaoFactoryBean实现FactoryBean<UserDao>接口
//FactoryBean创建对象
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
//代替原始实例工厂中创建对象的方法
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
public Class<?> getObjectType() {//获得UserDao的具体类型
return UserDao.class;
}
}
配置applicationContext.xml
<bean id="userDao" class="Factory.UserDaoFactoryBean"/>
依赖注入方式
setter注入
(XMl配置文件关键字:property)
引用类型:
简单类型:
构造方法注入
(XMl关键字:constructor-arg)
引用类型:
简单类型
如何选择依赖注入的方式:
- 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
- 可选依赖使用setter注入进行,灵活性强
- Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
- 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
- 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
- 自己开发的模块推荐使用setter注入
依赖自动装配
关键字:autowire
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>