Spring
我是用的 Spring 插件
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.18</version>
</dependency>
Spring 有什么优点
- 控制反转(IOC),面向切面编程 (AOP)
- 开源免费
- 轻量级非入侵框架
- 支持事务处理
- 对框架整合的支持(几乎对所有的java框架)
总结 —— Spring 是一个轻量级是控制反转(IOC),面向切面的框架(AOC)
Spring 有什么缺点
- 配置十分繁琐。配置地狱。非常可怕。所以我们后来使用 Spring Boot。
Spring 七大组成
Spring Boot
- 是一个快速开发的单个微服务框架
- 一个快速开发的脚手架
- 约定大于配置!(学习 maven 一样的)
Spring Cloud
- 基于 SpringBoot 实现
目前 java 工作情况
- 现在大多数的 java 工作都是用 Spring Boot 和 Spring Cloud。这两个框架都是基于 Spring 和 Spring MVC 来完成的。所以 Spring 非常重要!!!
Spring 里的 IOC
什么是IOC(控制反转)
-
由用户选择调用的方法,而不是以前的程序员手上(service层)就是控制反转
-
按照以前我们的一般操作就是通过在 serviceImpl 中创建 Dao 对象调用 DaoImpl 里具体执行的 Sql 语句。
但是如果我们想要在 Service 中根据一个 Dao 对象调用 不同的 DaoImpl 只能再次创建 Dao 对象并且调用 不同的 DaoImpl。
所以我们可以通过在 ServiceImpl 中给出 Dao 的 Set 接口来动态实现
public void setUserDao(UserDao userDao){ this.userDao = userDao; }就可以在创建 Service 对象调用 ServiceImpl 的方法时候,可以动态的通过 set 方法来选择 DaoImpl 就可以了。
-
这样的好处就是,如果我们在 DaoImpl 里创建的类,用户可以直接通过 Service 对象来调用,中间的步骤不需要修改。
-
这种思想,从本质上结局了问题,程序员不在需要管理对象的创建了。系统的耦合性大大降低,可以更多的专注在业务上。这是IOC原型
依赖注入
构造器注入
- 具体代码在 Spring-01-IOC、SPring-02-HelloSpring、Spring-03-IOC2
<bean id="user1" class="cn.hyz.pojo.User">
<!--有构造方法的第一种赋值: 通过类型赋值-->
<!--<constructor-arg type="java.lang.String" value="name1"/>-->
<!--有参构造方法的第二种赋值: 通过参数下标赋值-->
<!--<constructor-arg index="0" value="name1"/>-->
<!--有参构造方法的第三种赋值:通过形参名称赋值-->
<constructor-arg name="name" value="name2"/>
</bean>
Set 方式注入
- 依赖注入(Set 注入)
- 依赖:bean 对象的创建依赖容器
- 注入:bean 的所有属性赋值,由容器来完成。
【测试环境搭建】
-
复杂类型
package cn.hyz.pojo; /** * @author workplace * @date 2022/4/3 21:47 */ public class Address { private String address; public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "Address{" + "address='" + address + '\'' + '}'; } } -
真实对象
package cn.hyz.pojo; import java.util.*; /** * @author workplace * @date 2022/4/3 21:46 */ 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; } -
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"> <bean id="Address" class="cn.hyz.pojo.Address"> <property name="address" value="jluzh"/> </bean> <bean id="Student" class="cn.hyz.pojo.Student"> <!--普通注入:value--> <property name="name" value="hyz"/> <!--bean注入:ref--> <property name="address" ref="Address"/> <!-- 数组注入: <array> <value></value> <value></value> </array> --> <property name="books"> <array> <value>京瓶梅</value> <value>金瓶梅</value> <value>金品每</value> <value>静平美</value> </array> </property> <!--list注入 <list> <value>打篮球</value> <value>唱歌</value> <value>跳舞</value> </list> --> <property name="hobbies"> <list> <value>打篮球</value> <value>唱歌</value> <value>跳舞</value> </list> </property> <!--map注入: <map> <entry key="" value=""/> </map> --> <property name="card"> <map> <entry key="身份证" value="111111222222221111"/> </map> </property> <!--set注入: <set> <value>GTA5</value> <value>奇迹暖暖</value> <value>森林冰火人</value> </set> --> <property name="games"> <set> <value>GTA5</value> <value>奇迹暖暖</value> <value>森林冰火人</value> </set> </property> <!--null注入 <null/> --> <property name="wife"> <null/> </property> <!--Properties注入 <props> <prop key="">value</prop> <prop key="">value</prop> </props> --> <property name="info"> <props> <prop key="学号">17190424</prop> <prop key="姓名">hyz</prop> <prop key="性别">男</prop> </props> </property> </bean> </beans> -
测试类
package cn.hyz.test; import cn.hyz.pojo.Student; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author workplace * @date 2022/4/3 22:14 */ public class MyTest { @Test public void test() { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); Student student = (Student) context.getBean("Student"); System.out.println(student); } } -
结果
Student{name='hyz', address=Address{address='jluzh'}, books=[京瓶梅, 金瓶梅, 金品每, 静平美], hobbies=[打篮球, 唱歌, 跳舞], card={身份证=111111222222221111}, games=[GTA5, 奇迹暖暖, 森林冰火人], wife='null', info={学号=17190424, 性别=男, 姓名=hyz}}
拓展方式注入
-
p 命名空间注入 ----> 对应着 Set 方式注入
-
只需要在 xml 配置文件中的约束加上
xmlns:p="http://www.springframework.org/schema/p"就可以通过以下方式来注入属性
<!--p命名空间注入。通过 property 注入属性。property的意思--> <bean id="User1" class="cn.hyz.pojo.User" p:name="hyz" p:age="21"/> -
官方解释
-
-
c 命名空间注入 ----> 对应着构造器注入
-
只需要在 xml 配置文件中加上以下约束
xmlns:c="http://www.springframework.org/schema/c"就可以通过以下方式来注入属性
<!--c命名空间注入。通过构造器注入属性。constructor-arg 的意思--> <bean id="User2" class="cn.hyz.pojo.User" c:name="hyz" c:age="21"/> -
官方解释
-
-
注意点
-
不能直接使用 c 命名和 p 命名,需要先导入 xml 约束
xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c"
-
bean的作用域
-
单例模式 ----> singleton (是 spring 的默认模式)
<bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>从容器中 getBean 都是同一个对象
-
原型模式 ----> prototype
<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>每次从容器中 getBean 都产生一个新的对象
-
剩余的都只能在 web 开发中使用到。
Bean 自动装配
- 自动装配是 Spring 满足 bean 依赖的一种方式 ----> 给 ‘对象属性’ 赋值
- Spring 会在上下文中自动寻找,并自动给 bean 装配属性 ----> 自动给 ‘对象属性’ 赋值
在 Spring 中有三种装配的方式
-
在 xml 中显示的配置
<bean id="cat" class="cn.hyz.pojo.Cat"/> <bean id="dao" class="cn.hyz.pojo.Dog"/> <bean id="people" class="cn.hyz.pojo.People"> <property name="name" value="hyz"/> <property name="cat" ref="cat"/> <property name="dog" ref="dao"/> </bean> -
在 java 中显示的配置(还没学)
-
隐式地自动装配 bean
测试
环境搭建
- 一个人有两个宠物,一只猫一条狗!人一个类,猫一个类,狗一个类
自动装配
<!--
autowire:自动装配
byName:会在容器上下文里自动查找,和自己对象中 set 方法后面的忽略大小写值对应的 bean id。名字必须符合要求。
byType:会在容器上下文里自动查找,和自己对象中 ‘对象属性’ 相同对象类型的 bean。容器中只能由这一种的对象类型
-->
<bean id="people" class="cn.hyz.pojo.People" autowire="byType">
<property name="name" value="hyz"/>
</bean>
小结:
- byName 的时候,必须保证 对象的 id 符合规范(bean 的 id 必须是 ’对象类型’ )
- buType 的时候,必须保证 容器中只有一种对象类型(bean 的 class 不能重复)
使用注解实现自动装配
官方表示通过注解实现自动装配是要比通过 XML 配置文件实现自动装配要更好的。所以以后如果可以的话,尽量使用自动装配。
使用注解需知:
-
引入 xml 配置文件约束,增加 xmlns:context 约束,对 xsi:schemaLocation 内容进行修改。
xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd -
配置注解支持!这是所有使用注解的第一步!不仅仅是开启自动装配!
<context:annotation-config/>
-
使用示范
我们只需要在 ‘对象属性’ / ‘对象属性’Set方法 上添加
@Autowired注解,就可以为 ‘对象属性’ 自动装配。package cn.hyz.pojo; import org.springframework.beans.factory.annotation.Autowired; /** * @author workplace * @date 2022/4/3 23:50 */ public class People { // 加入 @Autowired 注解之后 ‘对象属性’自动装配 @Autowired private Dog dog; @Autowired private Cat cat; private String name; @Override public String toString() { return "People{" + "dog=" + dog + ", cat=" + cat + ", name='" + name + '\'' + '}'; } public Cat getCat() { return cat; } public void setCat(Cat cat) { this.cat = cat; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Dog getDog() { return dog; } public void setDog(Dog dog) { this.dog = dog; } }
-
注意:
-
使用 自动装配 的时候,你的 ’对象属性‘ 必须是在 IOC 容器里存在。
-
自动装配 默认使用
autowire="byType"完成,如果无法判断就会使用byName完成。所以请确保你的 对象 id 名称符合规范。
-
如果自动装配环境过于复杂,没有办法通过一个
@Autowired来完成。我们可以@Autowired配合@Qualifier(value = "对象 id")来指定一个唯一的对象自动装载。@Autowired @Qualifier(value = "cat") private Cat cat;
-
-
测试:如果
@Autowired定义了required属性为false。代表了这个属性可以为null。否则不允许为空// 加入 @Autowired 注解之后 ‘对象属性’自动装配 @Autowired private Dog dog; // 这里在 @Autowired 定义了 required 属性为 false。代表了这个属性可以为 null。否则不允许为空 @Autowired(required = false) private Cat cat;
Resource 注解
还有一种自动装配的方法,不用调用 Spring 的注解。就是通过使用 java 的原生注解 @Resource 来完成。
-
使用
@Resource private Dog dog; @Resource(name = "cat") private Cat cat; private String name; -
解释
它是先根据 byName 去容器内寻找对应的对象,如果没有符合调节就通过 byType 去容器里寻找。如果两个都没找到就会报错。
我们也可以通过
name = "对象 id"
@Resource 和 @Autowrite 区别
- 都可以实现自动装载,都可以放在 ‘对象属性’ 上
- @Autowrite 默认使用
autowire="byType"完成 - @Resource 默认使用 byName,找不到就使用 byType。两个都找不到就报错
- 我认为 @Resource 可以用在 Service 层,而 @Autowrite 可以用在 Servlet 层。
使用注解开发
使用注解前需要做的准备工作
-
在 Spring 之后使用注解开发必须存在 aop 的包
-
使用注解需要导入 context 约束,增加注解的支持
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!--开启注解支持--> <context:annotation-config/> <!--针对指定包路径下所有的类开启注解支持--> <context:component-scan base-package="cn.hyz.pojo"/> </beans>
Spring 注解和 ‘注解 和 xml 之间的关系’
-
Bean
- @Component
-
属性如何注入 ----> @Component
- @Value("value")
// @Component 等价于 <bean id="user" class="cn.hyz.pojo.User"/> 就是将对象放进容器里了 @Component public class User { // 等价与 <property name="name" value="hyz"/> @Value("hyz") public String name; } -
衍生的注解
@Component 有几个功能相同的衍生注解。我们在 web 开发中,会按照 mvc 三层架构分层
- dao ----> @Repository
- service ----> @Service
- controller ----> @Controller
-
自动装配设置
- @Autowrite 默认使用
autowire="byType"完成 - @Qualifier(value = "bean id")
- @Resource 默认使用 byName,找不到就使用 byType。两个都找不到就报错
- @Autowrite 默认使用
-
作用域 ----> 写在类上
- @Scope("singleton")
- @Scope("prototype")
-
小结
xml 和 注解
- xml 更加万能,适用于所有的场所!维护简单方便
- 注解 不是自己的类不能用,维护相对复杂。
xml 和 注解 工作中的应用场景
-
xml 用来管理bean
-
注解 只负责属性注入
-
我们在使用过程中,只需要注意一个问题:开启注解支持,选择 Spring 扫描的包
<!--开启注解支持--> <context:annotation-config/> <!--针对指定包路径下所有的类开启注解支持--> <context:component-scan base-package="cn.hyz.pojo"/>
使用 java 的方式配置 Spring
我们现在完全使用 Spring 的xml 配置,全权交给 java 来完成!
JavaConfig 是 Spring 的子项目,在 Spring 4 之后就成为了一个核心功能
配置类:等同于 xml
package cn.hyz.config;
import cn.hyz.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* @author workplace
* @date 2022/4/4 16:34
*/
/*
* MyConfig 也是在容器里托管的一个 bean
* @Configuration 代表了 MyConfig 是一个配置类,等价于 MyConfig.xml
* @ComponentScan 表示在 xml 中的 <context:component-scan base-package="packagePath"/>
* @Import(ClassName) 表示在 xml 中的 <import resource="XmlName"/>
* */
@Configuration
@ComponentScan("cn.hyz.pojo")
@Import(Myconfig2)
public class MyConfig {
/*
* 注册一个 Bean,就表示 xml 里面的 <bean></bean>
* 这个方法的名字就表示 <bean> 标签内的 id 属性
* 这个方法里的 return,就表示 <bean> 标签内的 class 属性
* */
@Bean
public User user() {
return new User();
}
}
实体类:
package cn.hyz.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @author workplace
* @date 2022/4/4 16:33
*/
@Component
public class User {
private String name;
public String getName() {
return name;
}
@Value("hyz")
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
测试类:
import cn.hyz.config.MyConfig;
import cn.hyz.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author workplace
* @date 2022/4/4 16:40
*/
public class MyTest {
@Test
public void test() {
/*
* 如果完全使用配置类这样子来做,我们只能通过 AnnotationConfig 来获取容器,通过配置类的 class 对象加载!
* */
ApplicationContext context
= new AnnotationConfigApplicationContext(MyConfig.class);
User getUser = (User) context.getBean("user");
System.out.println(getUser);
}
}