Spring 可从狭义与广义两个角度看待
狭义的 Spring 是指 Spring 框架(Spring Fremework)
广义的 Spring 是指 Spring 生态体系
Spring 框架是企业开发复杂性的一站式解决方案
Spring 框架的核心是 IoC 容器和 AOP 面向切面编程
Spring Ioc 负责创建与管理系统对象,并在此基础上扩展功能
4.1 IoC 控制反转:
(1)IoC 控制反转,全称是 Inverse of Control,是一种设计理念
(2)由代理人来创建与管理对象,消费者通过代理人来获取对象
(3)IoC 的目的是降低对象间的直接耦合
加入 IoC 容器将对象统一管理,让对象关联变为弱耦合
4.2 Ioc 容器是Spring生态的地基,用于统一创建和管理对象的依赖
4.3 Spring IoC 容器职责
(1)对象的控制权交由第三方统一管理(IoC控制反转)
(2)利用反射技术实现运行时对象创建与关联(DI依赖注入)
(3)基于配置提高应用程序的可维护性与扩展性
4.4 DI依赖注入
(1)IoC 是设计理念,是现代程序设计遵循的标准,是宏观目标
(2)DI (Dependency Injection) 是具体技术实现,是微观实现
(3)DI 在java中利用反射技术实现对象注入(Injection)
4.4.1 什么是对象依赖注入
依赖注入是指运行时将容器内对象利用反射赋给其他对象的操作
(1)基于Setter方法注入对象
<bean id="sweetApple" class="com.mkyuan.ioc.entity.Apple">
<property name="title" value="红富士">property>
<property name="color" value="红色">property>
<property name="origin" value="欧洲">property>
bean>
<bean id="lily" class="com.mkyuan.ioc.entity.Child">
<property name="name" value="莉莉">property>
<property name="apple" ref="sweetApple">property>
bean>
案例:
BookDao 类
public interface BookDao {
public void insert();
}
BookDaoImpl 类
public class BookDaoImpl implements BookDao{
@Override
public void insert() {
System.out.println("向 MySQL Book 表插入一条数据");
}
}
BookDaoOracleImpl 类
public class BookDaoOracleImpl implements BookDao{
@Override
public void insert() {
System.out.println("向 Oracle Book 表插入一条数据");
}
}
BookService 类
public class BookService {
private BookDao bookDao;
public BookDao getBookDao() {
return bookDao;
}
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void purchase(){
System.out.println("正在执行图书采购业务方法");
bookDao.insert();
}
}
applicationContext-dao.xml
<bean id="bookDao" class="com.mkyuan.ioc.bookshop.dao.BookDaoOracleImpl">bean>
可通过选择Dao接口下不同的实现类注入对象
applicationContext-service.xml
<bean id="bookService" class="com.mkyuan.ioc.bookshop.service.BookService">
<property name="bookDao" ref="bookDao">property>
bean>
BookShopApplication 类
public class BookShopApplication {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext-*.xml");
BookService bookService = context.getBean("bookService", BookService.class);
bookService.purchase();
}
}
(2)基于构造方法注入对象
<bean id="sweetApple" class="com.mkyuan.ioc.entity.Apple">
<property name="title" value="红富士">property>
<property name="origin" value="欧洲">property>
<property name="color" value="红色">property>
bean>
<bean id="lily" class="com.mkyuan.ioc.entity.Child">
<property name="name" value="莉莉">property>
<property name="apple" ref="sweetApple">property>
bean>
4.4.2 注入集合对象
Company 类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Company {
private Set<String> rooms;
private Map<String, Computer> computers;
private Properties info;
}
Computer 类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Computer {
private String brand;
private String type;
private String sn;
private Float price;
}
applicationContext.xml
<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="c1" class="com.mkyuan.ioc.entity.Computer">
<constructor-arg name="brand" value="联想">constructor-arg>
<constructor-arg name="type" value="台式机">constructor-arg>
<constructor-arg name="sn" value="8389283012">constructor-arg>
<constructor-arg name="price" value="3085">constructor-arg>
bean>
<bean id="company" class="com.mkyuan.ioc.entity.Company">
<property name="rooms">
<set>
<value>2001-总裁办value>
<value>2003-总经理办公室value>
<value>2010-研发部会议室value>
<value>2010-研发部会议室value>
set>
property>
<property name="computers">
<map>
<entry key="dev-88172" value-ref="c1">entry>
<entry key="dev-88173">
<bean class="com.mkyuan.ioc.entity.Computer">
<constructor-arg name="brand" value="联想">constructor-arg>
<constructor-arg name="type" value="笔记本">constructor-arg>
<constructor-arg name="sn" value="8389283012">constructor-arg>
<constructor-arg name="price" value="5060">constructor-arg>
bean>
entry>
map>
property>
<property name="info">
<props>
<prop key="phone">010-12345678prop>
<prop key="address">深圳市xxx路xx大厦prop>
<prop key="website">http://www.xxxx.comprop>
props>
property>
bean>
beans>
SpringApplication 类
public class SpringApplication {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Company company = context.getBean("company", Company.class);
String website = company.getInfo().getProperty("website");
System.out.println(website);
System.out.println(company);
}
}
4.4.3 查看容器内对象
SpringApplication
public class SpringApplication {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Company company = context.getBean("company", Company.class);
String website = company.getInfo().getProperty("website");
System.out.println(website);
System.out.println(company);
System.out.println("========================");
//获取容器内所有BeanId数组
String[] beanNames = context.getBeanDefinitionNames();
for (String beanName : beanNames) {
System.out.println(beanName);
System.out.println("类型:"+context.getBean(beanName).getClass().getName());
System.out.println("内容:"+context.getBean(beanName));
}
}
}
5.1.案例:
(1)妈妈在早餐后给三个孩子分发餐后水果
(2)盘子里装有三个水果:红富士/青苹果/金帅
(3)孩子们口味不同:莉莉喜欢甜的/安迪喜欢酸的/露娜喜欢软的
如何让孩子得到喜欢的苹果
5.1.1 普通方式
Apple 类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Apple {
private String title;
private String color;
private String origin;
}
Child 类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Child {
private String name;
private Apple apple;
public void eat() {
System.out.println(name + "吃到了" + apple.getOrigin() + "种植的" + apple.getTitle());
}
}
Application 类
public class Application {
public static void main(String[] args) {
Apple apple1 = new Apple("红富士", "红色", "欧洲");
Apple apple2 = new Apple("青苹果", "绿色", "中亚");
Apple apple3 = new Apple("金帅", "黄色", "中国");
Child lily = new Child("莉莉", apple1);
Child andy = new Child("安迪", apple2);
Child luna = new Child("露娜", apple3);
lily.eat();
andy.eat();
luna.eat();
}
}
5.1.2 IoC 方式
引入依赖
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.2.9.RELEASEversion>
dependency>
创建 applicationContext.xml
<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="sweetApple" class="com.mkyuan.ioc.entity.Apple">
<property name="title" value="红富士">property>
<property name="origin" value="欧洲">property>
<property name="color" value="红色">property>
bean>
<bean id="sourApple" class="com.mkyuan.ioc.entity.Apple">
<property name="title" value="青苹果">property>
<property name="origin" value="中亚">property>
<property name="color" value="绿色">property>
bean>
<bean id="softApple" class="com.mkyuan.ioc.entity.Apple">
<property name="title" value="金帅">property>
<property name="origin" value="中国">property>
<property name="color" value="黄色">property>
bean>
<bean id="lily" class="com.mkyuan.ioc.entity.Child">
<property name="name" value="莉莉">property>
<property name="apple" ref="sweetApple">property>
bean>
<bean id="andy" class="com.mkyuan.ioc.entity.Child">
<property name="name" value="安迪">property>
<property name="apple" ref="sourApple">property>
bean>
<bean id="luna" class="com.mkyuan.ioc.entity.Child">
<property name="name" value="露娜">property>
<property name="apple" ref="softApple">property>
bean>
beans>
SpringApplication 类
public class SpringApplication {
//创建 spring IoC 容器,并且根据配置文件在容器中实例化对象
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
Apple sweetApple = context.getBean("sweetApple", Apple.class);
System.out.println(sweetApple);
Child lily = context.getBean("lily", Child.class);
lily.eat();
Child andy = context.getBean("andy", Child.class);
andy.eat();
Child luna = context.getBean("luna", Child.class);
luna.eat();
}
6.1 基于 XML 配置 bean
(1)基于构造方法实例化对象
<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="apple1" class="com.mkyuan.ioc.entity.Apple">
bean>
<bean id="apple2" class="com.mkyuan.ioc.entity.Apple">
<constructor-arg name="title" value="红富士">constructor-arg>
<constructor-arg name="color" value="红色">constructor-arg>
<constructor-arg name="origin" value="欧洲">constructor-arg>
<constructor-arg name="price" value="19.8">constructor-arg>
bean>
<bean id="apple3" class="com.mkyuan.ioc.entity.Apple">
<constructor-arg index="0" value="红富士">constructor-arg>
<constructor-arg index="1" value="红色">constructor-arg>
<constructor-arg index="2" value="欧洲">constructor-arg>
<constructor-arg index="3" value="19.8">constructor-arg>
bean>
beans>
(2)基于静态工厂实例化对象
AppleStaticFactory 类
/**
* 静态工厂通过静态方法创建对象,隐藏创建对象的细节
*/
public class AppleStaticFactory {
public static Apple createSweetApple() {
Apple apple = new Apple();
apple.setTitle("红富士");
apple.setOrigin("欧洲");
apple.setColor("红色");
return apple;
}
}
<bean id="apple4" class="com.mkyuan.ioc.factory.AppleStaticFactory" factory-method="createSweetApple">
bean>
(3)基于工厂实例方法实例化对象
AppleFactoryInstance 类
/**
* 工厂实例方法创建对象是指 Ioc 容器对工厂进行实例化并调用对应的实例方法创建对象的过程
*/
public class AppleFactoryInstance {
public Apple createSweetApple() {
Apple apple = new Apple();
apple.setTitle("红富士");
apple.setOrigin("欧洲");
apple.setColor("红色");
return apple;
}
}
<bean id="factoryInstance" class="com.mkyuan.ioc.factory.AppleFactoryInstance">bean>
<bean id="apple5" factory-bean="factoryInstance" factory-method="createSweetApple">
bean>
6.1.1 id和name属性相同点
(1)bean id与 name 都是设置对象在 IoC 容器中唯一标示
(2)两者在同一个配置文件中都不允许出现重复
(3)两者允许在多个配置文件中出现重复对象,新对象覆盖旧对象
6.1.2 id和name属性区别
(1)id 更为严格,一次只能定义一个对象标示(推荐)
(2)name 更为宽松,一次允许定义多个对象标示
<bean name="apple2,apple7" class="com.mkyuan.ioc.entity.Apple">
<constructor-arg name="title" value="红富士2号">constructor-arg>
<constructor-arg name="color" value="红色">constructor-arg>
<constructor-arg name="origin" value="欧洲">constructor-arg>
<constructor-arg name="price" value="29.8">constructor-arg>
bean>
(3)id 与 name 的命名要求有意义,按照驼峰命名书写
(4) 没有id和name默认使用类名全称作为bean标示
<bean class="com.mkyuan.ioc.entity.Apple">
<constructor-arg name="title" value="红富士3号">constructor-arg>
<constructor-arg name="color" value="红色">constructor-arg>
<constructor-arg name="origin" value="欧洲">constructor-arg>
<constructor-arg name="price" value="29.8">constructor-arg>
bean>
Apple apple2 = context.getBean("com.mkyuan.ioc.entity.Apple", Apple.class);
System.out.println(apple2);
6.2 基于注解配置 bean
6.2.1 基于注解的优势
(1)摆脱繁琐的XML形式的bean与依赖注入的配置
(2)基于"声明式"的原则,更适合轻量级的现代企业的应用
(3)让代码的可读性变的更好,研发人员拥有更好的开发体验
6.2.2 三类注解
(1)组件类型注解-声明当前类的功能与职责
(2)自动装配注解-根据属性特征自动注入对象
(3)元数据注解-更细化的辅助 IoC 容器管理对象的注解
6.3 基于 java 代码配置 bean
Config 类
@Configuration
@ComponentScan(basePackages = "com.mkyuan")
public class Config {
@Bean
public UserDao userDao() {
UserDao userDao = new UserDao();
System.out.println("已创建:" + userDao);
return userDao;
}
@Bean
@Primary
public UserDao userDao1() {
UserDao userDao = new UserDao();
System.out.println("已创建:" + userDao);
return userDao;
}
@Bean
public UserService userService(UserDao userDao, EmployeeDao employeeDao) {
UserService userService = new UserService();
System.out.println("已创建:" + userService);
userService.setUserDao(userDao);
System.out.println("调用setUserDao:" + userDao);
userService.setEmployeeDao(employeeDao);
System.out.println("调用setEmployeeDao:" + employeeDao);
return userService;
}
@Bean
@Scope("prototype")
public UserController userController(UserService userService) {
UserController userController = new UserController();
System.out.println("已创建:" + userController);
userController.setUserService(userService);
System.out.println("调用setUserService:" + userService);
return userController;
}
}
7.1 bean scope属性
bean scope属性用于决定对象何时被创建与作用范围
bean scope 配置将影响容器内对象的数量
bean scope 默认值singleton(单例),指全局共享一个对象实例,默认情况下bean会在 Ioc 容器创建后自动实例化,全局唯一
7.2 singleton与 prototype 对比
Order 类
public class Order {
private Float price;
private Integer quantity;
private Float total;
public Order() {
System.out.println("创建Order对象," + this);
}
public void init() {
System.out.println("执行init方法");
total = price * quantity;
}
public void destroy() {
System.out.println("释放与订单对象相关的资源");
}
public void pay() {
System.out.println("订单金额为:" + total);
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
System.out.println("设置price:" + price);
this.price = price;
}
public Integer getQuantity() {
return quantity;
}
public void setQuantity(Integer quantity) {
System.out.println("设置quantity:" + quantity);
this.quantity = quantity;
}
public Float getTotal() {
return total;
}
public void setTotal(Float total) {
this.total = total;
}
}
applicationContext.xml
<bean id="order1" class="com.mkyuan.ioc.entity.Order" init-method="init" destroy-method="destroy">
<property name="price" value="19.8">property>
<property name="quantity" value="20">property>
bean>
SpringApplication 类
public class SpringApplication {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("==========IoC容器已初始化=============");
Order order1 = context.getBean("order1", Order.class);
order1.pay();
((ClassPathXmlApplicationContext) context).registerShutdownHook();
}
}
执行结果