-
-
- 极可能让类与类之间的关联降到最低
-
-
- 原则
-
-
- 责任单一原则
-
-
-
-
- 需要用整个编程生涯来贯彻
-
-
-
-
- 最少知道原则
-
-
-
-
- 禁止跨级调用
- 让一个类,认识/调用 最少的类
-
-
- 简化事务
-
- 事务:添加修改删除,出错了,回滚
- 仅仅使用一个注解,就能让事务生效
- 集成了JUnit,方便测试
- 简化了开发
- 方便集成各种框架
-
- 使用Spring去管理所有的框架
控制反转(IOC)
正常情况下,对象的控制器,在程序员手中
反转了,交出了控制权,不再是每次使用对象的时候亲自new对象,而是交给了Spring容器去new对象,每次使用对象的时候,问Spring要
bean对象装到容器中
创建Spring项目
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
</dependencies>
- 依赖导入成功之后,创建配置文件
- 管理bean(都要有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">
<!--当前的Student类交给了Spring容器去创建-->
<bean id="abc" class="com.javasm.demo.Student"/>
</beans>
- 测试类
private static void test1() {
//从类加载路径中,加载配置文件spring1.xml
//读取配置文件中的内容
//解析xml标签
//创建一个bean的集合,new一个对象,存入bean的集合等待调用
//applicationContext 实际上就是Spring容器对象
//不论是否调用bean对象,在Spring容器初始化的时候,都会创建bean对象
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext("spring1.xml");
//从Spring容器中,寻找id=abc的bean对象
Student abc = (Student) applicationContext.getBean("abc");
//赋值
abc.setId(100);
abc.setName("张三");
abc.setAge(11);
System.out.println(abc);
}
启动原理
程序启动 → 读取xml文件 → 解析xml配置文件 → 读取了bean标签的内容 → 通过反射,初始化bean对象(new对象) → bean对象 存入Spring容器,等待调用
private static void test4() throws Exception{
Student abc = (Student) test3("abc");
//赋值
abc.setId(100);
abc.setName("张三");
abc.setAge(11);
System.out.println(abc);
}
//获取bean对象
private static Object test3(String id) throws Exception {
Map<String, Object> map = test2();
Object o = map.get(id);
return o;
}
private static Map<String,Object> test2() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//<bean id="abc" class="com.javasm.demo.Student"/>
String id = "abc";
String className = "com.javasm.demo.Student";
//通过反射,new对象
Class<?> aClass = Class.forName(className);
//bean对象
Object o = aClass.getConstructor().newInstance();
//创建一个容器
Map<String,Object> springApplication = new ConcurrentHashMap<>();
springApplication.put(id,o);
return springApplication;
}
获取Bean的方式
//根据id获取bean
Student abc = (Student) context.getBean("abc");
//根据类型获取
Student student = context.getBean(Student.class);
//根据ID +类型
Student abc1 = context.getBean("abc", Student.class);
别名
<!--别名,不常用-->
<alias name="stu" alias="s"/>
Student s = context.getBean("s", Student.class);
创建Bean的方式
- 无参构造
<bean id="abc" class="com.javasm.demo.Student"/>
- 静态工厂
<bean id="xiaoming" class="com.javasm.demo.StudentStaticFactory" factory-method="getStudent"/>
public class StudentStaticFactory {
public static Student getStudent(){
Student student = new Student();
student.setName("小明");
return student;
}
}
- 实例工厂
<bean id="stuFactory" class="com.javasm.demo.StudentFactory"/>
<bean id="xiaohong" factory-bean="stuFactory" factory-method="getStudent"/>
public class StudentFactory {
public Student getStudent(){
Student student = new Student();
student.setName("小红");
return student;
}
}
- Spring工厂
<!--Spring工厂-->
<bean id="huowang" class="com.javasm.demo.StudentSpringFactory"/>
public class StudentSpringFactory implements FactoryBean<Student> {
@Override
public Student getObject() throws Exception {
//返回的对象是什么,Spring容器中存什么
Student student = new Student();
student.setName("李火旺");
return student;
}
@Override
public Class<?> getObjectType() {
return Student.class;
}
@Override
public boolean isSingleton() {
//是否是单例
//true:单例
//false:多例
//默认是true
return true;
}
}
单例
Spring的bean对象,在默认情况下,都是单例的
加上scope="prototype"将不是单例
<bean id="teacher" class="com.javasm.demo.Teacher" scope="prototype"/>
单例:Spring启动 → 加载解析XML文件 → 创建Bean对象 →bean保存到容器 →随着容器关闭销毁
多例:Spring启动→加载解析XML文件→先把解析的内容记录下来→调用的时候创建bean
懒加载
不使用不创建对象
仅仅对单例生效
<bean id="teacher1" class="com.javasm.demo.Teacher" lazy-init="true"/>
全局配置
<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"
default-lazy-init="true"
>
初始化&销毁
<bean id="teacher2" class="com.javasm.demo.Teacher" init-method="test1" destroy-method="test2"/>
test1 和 test2 是普通的方法
构造方法
初始化方法
正常调用方法
---销毁
关闭容器
依赖注入(DI)
以来的对象,从Spring容器中获取,而非自己new
- 测试类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Game {
private Integer id;
private String name;
private Double price;
//公司
private Company company;
//英雄列表
private String[] heros;
//关卡
private List<String> levels;
//背包
private Map<Integer,String> items;
//成就
private Set<String> achievements;//不包含重复元素
//游戏配置
private Properties gameConfig;
//玩家列表
private List<Player> playerList;
}
@Data
public class Company {
private String name;
private String address;
}
@Data
public class Player {
private Integer id;
private String nickname;
}
<?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 id="game" class="com.javasm.demo2.Game">
<property name="id" value="1000"/>
<property name="name" value="黑悟空"/>
<property name="price" value="648.88"/>
<!--公司-->
<property name="company" ref="company"/>
<!--影响列表-->
<property name="heros">
<array>
<value>孙悟空</value>
<value>杨戬</value>
<value>哪吒</value>
</array>
</property>
<!--关卡-->
<property name="levels">
<list>
<value>黑风寨</value>
<value>黄风岭</value>
<value>小西天</value>
</list>
</property>
<!--背包-->
<property name="items">
<map>
<entry key="1001" value="金箍棒"/>
<entry key="1002" value="三尖两刃刀"/>
<entry key="1003" value="定风珠"/>
</map>
</property>
<!--成就-->
<property name="achievements">
<set>
<value>借刀杀人</value>
<value>顺手牵羊</value>
<value>万箭齐发</value>
</set>
</property>
<!--配置-->
<property name="gameConfig">
<props>
<prop key="location">zh</prop>
<prop key="model">全屏</prop>
</props>
</property>
<property name="playerList">
<list>
<bean class="com.javasm.demo2.Player">
<property name="id" value="1001"/>
<property name="nickname" value="泉水指挥官"/>
</bean>
<ref bean="xiaoheizi"/>
</list>
</property>
</bean>
<bean id="company" class="com.javasm.demo2.Company">
<property name="name" value="游戏科学"/>
<property name="address" value="郑州863软件园"/>
</bean>
<bean id="xiaoheizi" class="com.javasm.demo2.Player">
<property name="id" value="1002"/>
<property name="nickname" value="小黑子"/>
</bean>
</beans>
自动装配
<!--autowire 自动装配: byType、 根据属性的类型,去Spring容器中寻找对应的bean对象,如果找到了,自动赋值给对应的属性-->
<bean id="g2" class="com.javasm.demo2.Game" autowire="byType"/>
<!--根据属性的名字,去寻找id和属性名一样的bean,属性名称为类的私有变量名-->
<bean id="g3" class="com.javasm.demo2.Game" autowire="byName"/>
全局
<?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"
default-autowire="byName"
>
构造方法的注入
<?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 id="company" class="com.javasm.demo2.Company">
<property name="name" value="尚马"/>
</bean>
<!--
index:构造方法第几个参数
name: 构造方法的参数名称
推荐使用index配置参数
-->
<bean id="music" class="com.javasm.demo3.Music">
<constructor-arg value="100" name="id" type="java.lang.Integer"/>
<constructor-arg index="1" value="云顶天宫"/>
<constructor-arg index="2" value="10分钟"/>
<constructor-arg index="3" ref="company"/>
</bean>
</beans>
@Data
public class Music {
public Music() {
}
public Music(Integer id, String name, String time, Company company) {
this.id = id;
this.name = name;
this.time = time;
this.company = company;
}
private Integer id;
private String name;
private String time;
private Company company;
}
异常
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'abcd' available
bean的id写错了,没有找到名字是abcd的bean对象
Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.javasm.demo.Student' available: expected single matching bean but found 2: abc,stu
根据类型,从Spring容器中获取bean对象,但是容器中有两个bean对象,是相同类型的,所以报错
因为我要找1个bean,但是发现了2个
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'teacher' defined in class path resource [spring1.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.javasm.demo.Teacher]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.javasm.demo.Teacher.<init>()
Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'teacher' defined in class path resource [spring1.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.javasm.demo.Teacher]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.javasm.demo.Teacher.<init>()
因为类中没有无参构造,报错
养成一个习惯,只要写有参构造,不论是否需要无参构造,都要写一个