20191012
一 Spring
1 简介
1.1 概述
- 2002年推出了雏形interface21,2004年推出了第一个版本
- 核心 Fimaword ,创始人:Rod Johnson,悉尼大学的音乐博士
- 理念本身就是一个大杂烩,整合了所有的框架
1.2 常见的框架
- SSH (SStruct+Spring+Hibernate)
- SSM(SpringMVC+Spring+Mybatis)
1.3 下载Spring
官网:https://spring.io/projects/spring-framework#overview
官方下载地址: http://repo.spring.io/release/org/springframework/spring
GitHub:https://github.com/spring-projects/spring-framework
1.4 SpringJAR包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
2 优点缺点
Spring是一个轻量级控制反转(IOC)和面向切面编程(AOP)的框架
优点:
- 开源的,免费框架(容器)
- 轻量级,非入侵式
- 控制反转(IOC),面向切面(AOP)
- 支持事务处理.对框架进行整合
缺点 - 配置地域,整合的配置太多
3 组成
简单的介绍
- AOP:提供了一个符合其联盟标准的面向切面编程实现。
- Test:支持JUnit和TestNG对Spring组件测试.
- 其他的都一样
4 拓展
构建 协调 连接
4.1 现代性的java开发==Spring开发
4.2 Spring Boot
4.2.1 一个快速开发的脚手架
4.2.2 基于可快速开发微服务
4.2.3 约定大于配置
4.2.3.1 - [ ] 约定大于配置的解释
约定
开发人员只需要规定不符合约定的地方配置
没有规定用配置的地方就用默认的配置,力求配置的简洁化,规定需要用配置的地方就使用自定义配置Spring Boot中的约定?
- Meavn结构目录,resources中以前存放的是配置文件,现在,java+resources以及默认的编译生成的类都在targe文件夹下面
- Spring boot命名的文件必须是application.yml文件或者.properties文件,且唯一
- application.yml中默认属性。数据库连接信息必须是以spring: datasource: 为前缀;多环境配置。该属性可以根据运行环境自动读取不同的配置文件;端口号、请求路径等
4.3 Spring Cloud
- SpringCloud 是基于SpringBoot实现的。
- 大多数公司开发使用SpringBoot ,SpringBoot之前要深入了解 Spring SpringMVC
二 IOC理论推导
1.1 概念
-
控制反转:控制权从从程序员手中回到了用户手中
-
一种设计思想(不要打电话了我们会打给你的),你的对象不由你控制,由容器控制(Spring),id(依赖注入)实现了这种方法
-
谁控制谁,控制什么?
传统的控制:我们直接在对象的内部进行new 对象,程序主动去创建依赖
loc 容器控制对象,控制了外部资源(对象/文件)
- 反转?都反转了那些东西?=
正转?有反转就有正转:程序在对象的内部进行new 对象,程序主动去创建依赖
为什么是反转?是容器帮我们注入依赖了对象,对象是被依赖
反转了什么?依赖对象的获取
1 开发异同
1.1 传统开发 IOC使用后开发
-
UserDao 接口
-
UserDaoImpl 实现类
-
UserService 业务接口
-
UserServiceImpl 业务实现类
-
需要改的话得回到Service中,现在只需要在test中进行修改
2 开发步骤
- 创建一个一般的Meavn项目
- 补全包结构
- pom文件,添加依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
- user类(有参构造)
package com.lala.pojo;
/**
* @Description:TODO
* @Author:@李小白
* @Date:2019/10/12 10:57
*/
public class User {
// 有参构造进行默认的实现
private String name;
public User(String name) {
this.name = name;
System.out.println("user有参构造");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("show"+name);
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
- user2(无参构造)
package com.lala.pojo;
/**
* @Description:TODO
* @Author:@李小白
* @Date:2019/10/12 10:57
*/
public class User2 {
// 无参构造,默认实现
private String name;
public User2() {
System.out.println("无参构造");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User2{" +
"name='" + name + '\'' +
'}';
}
}
有参构造和无参构造的区别就是
-
constructor-arg 有参
-
property 无参
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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--任意调用一个,有参无参会同时创建,输出(因为所有的bean是同一个对象被Spring实例化)-->
<!--有参构造 ,实现有三种方式-->
<!--参数赋值(常用) 下表赋值 类型赋值(不建议使用)-->
<!--id:对象名
class:bean的权限定名 包+类型
name:别名,可以用,空格 分号 进行分割
-->
<bean id="user" class="com.lala.pojo.User" name="u2,u3 u4;u5">
<constructor-arg name="name" value="李强娜"/>
<!--<constructor-arg index="0" value="李强娜"></constructor-arg>-->
<!--<constructor-arg type="java.lang.String" value="李强娜"></constructor-arg>-->
</bean>
<!--无参构造的方式-->
<bean id="user2" class="com.lala.pojo.User2">
<property name="name" value="李强娜2"></property>
</bean>
<!--bean 的配置-->
<!--import:一般用于团队的开发使用,导入合并为一个-->
<!--给user起别名,一般没有用,name更高级可以取多个别名 -->
<alias name="user" alias="dfsdvsdvds"></alias>
<!---->
</beans>
- bean2.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--凑数-->
<bean id="user" class="com.lala.pojo.User" name="u2,u3 u4;u5">
<constructor-arg name="name" value="李强娜"/>
</bean>
</beans>
- applicationContext.xml
导入import
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--假如项目中有好多个bean-->
<!--将2个bean汇总到一个里面进行汇总-->
<import resource="beans.xml"></import>
<import resource="beans2.xml"></import>
</beans>
- 测试类(原始的和现在的进行对比)
import com.lala.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Description:TODO
* @Author:@李小白
* @Date:2019/10/12 11:02
*/
public class MyText {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml.xml");
User user = (User) context.getBean("user");
user.show();
System.out.println(user.toString());
}
}
- 项目外,传统的和现在的进行对比
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.westos.pojo.UserOrcialDaoImpl;
import org.westos.service.UserService;
import org.westos.service.UserServiceImpl;
/**
* @Description:IOC理论第一个,再进行改良
* @Author:@李小白
* @Date:2019/10/9 22:09
*/
public class MyTest {
public static void main(String[] args) {
//原始的进行获取
//UserService userService = new UserServiceImpl();
//1.获取ApplicationContext对象,拿到容器
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//在里面进行改动你要输出的数据
//((UserServiceImpl) userService).setUserDao(new UserOrcialDaoImpl());
//userService.getUser();
//容器在手,天下我有,需要什么就get什么,,(里面的是bean的名字)
UserServiceImpl userServiceImpl = (UserServiceImpl) context.getBean("applicationContext");
//调用方法
userServiceImpl.getUser();
//在获取的时候也不用这样的进行获取了,就得到String的上下文的对象,并且调用相应的beans
//调用beans的名字,强转成他所需要的类型
}
}
2.0 约束区官网搜
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
2.1 标签的意思
- beans.xml
- bean=String
- id=唯一标识符的对象名
- class=bean的权限定名
- name=别名(多个别名之间用, ; 空格 都额可以)
2.2 创建对象的三种方法
-
三种创建方法,最常用name
<!--<constructor-arg index="0" value="李强娜"></constructor-arg>--> <!--<constructor-arg type="java.lang.String" value="李强娜"></constructor-arg>--> <!-- <constructor-arg name="name" value="李强娜"/>-->
2.3 起别名
方式一
<!--给user起别名,一般没有用,name更高级可以取多个别名 -->
<alias name="user" alias="dfsdvsdvds"></alias>
方式二
<!--给user起别名,name更高级可以取多个别名 -->
<bean id="user" class="com.lala.pojo.User" name="u2,u3 u4;u5"></bean>
2.4 导入汇总import
<import resource="beans.xml"></import>
<import resource="beans2.xml"></import>
2.5 bean中单例模式和原型模式 ?
3 DI 依赖注入[重点]
3.1 常见的3种构造器注入(前面有)
3.2 set方式注入
3.2.1 简单的set注入
- Persion 类
public class Persion {
private Man man;
private String sex;
public Man getMan() {
return man;
}
public void setMan(Man man) {
this.man = man;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Persion{" +
"man=" + man +
", sex='" + sex + '\'' +
'}';
}
}
- man类
public class Man {
private String sex;
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
- bean
<bean id="man" class="com.lala.pojo.Man">
<property name="sex" value="女"></property>
</bean>
<bean id="persion" class="com.lala.pojo.Persion">
<property name="man" ref="man"></property>
<property name="sex" value="男"></property>
</bean>
- 测试类
ApplicationContext context = new ClassPathXmlApplicationContext("beans1.xml");
Persion persion = (Persion) context.getBean("persion");
System.out.println(persion.toString());
- 执行结果
Persion{man=com.lala.pojo.Man@100d6b1, sex='男'}
3.2.1 复杂的set注入
- Student 类
@Data
public class Student {
private String name;
private String[] books;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> games;
private String wife;
private Properties info;
}
beans
<bean id="student" class="com.lala.pojo.Student">
<!--普通的-->
<property name="name" value="李强娜"></property>
<!--数组-->
<property name="books" >
<array>
<value>我在未来等你</value>
<value>愿风裁尘</value>
</array>
</property>
<!--list-->
<property name="hobbys">
<list>
<value>宅在家里</value>
<value>和喜欢的在一起</value>
<value>宅在家里</value>
</list>
</property>
<!--map-->
<property name="card">
<map>
<entry key="章晗" value="李强娜"></entry>
<entry key="名字" value="不知道"></entry>
<entry key="密码" value="521"></entry>
</map>
</property>
<!--set-->
<property name="games">
<set>
<value>都是数据</value>
<value>都是数据</value>
</set>
</property>
<!--null注入-->
<property name="wife">
<null></null>
</property>
<!--properties-->
<property name="info">
<props>
<prop key="driver">driver</prop>
<prop key="url">url</prop>
<prop key="username">username</prop>
<prop key="password">password</prop>
</props>
</property>
</bean>
结果
Student{name='李强娜', books=[我在未来等你, 愿风裁尘], hobbys=[宅在家里, 和喜欢的在一起, 宅在家里], card={章晗=李强娜, 名字=不知道, 密码=521}, games=[都是数据], wife='null', info={password=password, url=url, driver=driver, username=username}}
4 扩展方式注入(c p)
- 使得代码更加简洁
- 和前面的程序一样
- 官网搜
bean中加入C P 约束
- xmlns:p=“http://www.springframework.org/schema/p”
xmlns:c=“http://www.springframework.org/schema/c”
<?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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student" class="com.lala.pojo.Student" c:name="李强娜"/>
<bean id="student2" class="com.lala.pojo.Student" c:name="李强娜2"/>
</beans>
bean 作用域
-
单例模式 (Spring默认机制)
<bean id="user2" class="com.kuang.pojo.User" c:age="18" c:name="狂神" scope="singleton"/>
-
原型模式:每次从容器中get的时候,都会产生一个新对象!
<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>
-
其余的 request、session、application、这些个只能在web开发中使用到!
5 Bean的自动装配
5.1 什么是自动装配
- 自动装配是Spring满足bean依赖一种方式!
- Spring会在上下文中自动寻找,并自动给bean装配属性!
在Spring中有三种装配的方式
- 在xml中显示的配置
- 在java(接口和类)中显示配置
- 隐式 的自动装配bean 【重要】
5.2 改如何选择这三种装配方式
- 隐式装配
约定大于配置
优点:减少程序员去定义,让程序更加简单灵活
- java中接口和类
需要手动装配的时候使用
优点:解决xml 带来的弊端
- xml
简单
优点:初学者易懂,任何场合都可以使用
缺点,难维护,里面的代码不是自己的
- 注解
简单,有效的减少代码的量
缺点:不是自己的类不可以使用
5.3 xml 装配
5.3.1 手动装配
pojo
Cat
public class Cat {
public void voice(){
System.out.println("喵喵喵!");
}
}
Dog
public class Dog {
public void voice(){
System.out.println("汪汪汪!");
}
}
Animal
public class Animal {
private String name;
private Cat cat;
private Dog dog;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
public String toString() {
return "Animal{" +
"name='" + name + '\'' +
", cat=" + cat +
", dog=" + dog +
'}';
}
}
bean
<bean id="cat" class="com.lala.pojo.Cat"></bean>
<bean id="dog" class="com.lala.pojo.Dog"></bean>
<bean id="animal" class="com.lala.pojo.Animal">
<property name="name" value="动物园"></property>
<property name="cat" ref="cat"></property>
<property name="dog" ref="dog"></property>
</bean>
测试文件
ApplicationContext context = new ClassPathXmlApplicationContext("base.xml");
Animal animal = (Animal) context.getBean("animal");
animal.getCat().voice();
animal.getDog().voice();
5.3.2 By Name式自动装配 autowire=“byName”
byName: 会自动在容器上下文中查找,和自己对象set方法后面的值对应的 beanid!
-->
<bean id="cat" class="com.lala.pojo.Cat"/>
<bean id="dog" class="com.lala.pojo.Dog"/>
<bean id="student" class="com.lala.pojo.Animal" autowire="byName">
<property name="name" value="张三"/>
</bean>
id 可以省略
前提是 和 set 后面的name 唯一
5.3.3 ByType式自动装配 autowire=“byType”
1.可以不用写ref
<bean id="cat" class="com.lala.pojo.Cat"/>
<bean id="dog" class="com.lala.pojo.Dog"/>
<bean id="student" class="com.lala.pojo.Animal" autowire="byType">
<property name="name" value="动物园"/>
</bean>
2.id 写错的情况
<bean id="cats1" class="com.lala.pojo.Cat"/>
<bean id="dogs1" class="com.lala.pojo.Dog"/>
<bean id="student" class="com.g.pojo.Student" autowire="byType">
<property name="name" value="动物园"/>
</bean>
3.可以直接不用写id
<bean class="com.lala.pojo.Cat"/>
<bean class="com.lala.pojo.Dog"/>
<bean id="student" class="com.lala.pojo.Student" autowire="byType">
<property name="name" value="动物园"/>
</bean>
可以删掉 id 只要calss唯一
小结:
- byname的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致!
- bytype的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!
5.3.4 使用半注解实现半xml实现装配
== jdk1.5支持的注解,Spring2.5就支持注解了!==
要使用注解须知:
- @Autowired
直接在属性上使用即可!也可以在set方式上使用!
使用Autowired 我们可以不用编写Set方法了,前提是你这个自动装配的属性在 IOC(Spring)容器中存在,且符合名字byname!
- @Nullable
表示可以为空
- @Qualifier
如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候、我们> 可以使用@Qualifier(value=“xxx”)去配置@Autowired的使用,指定一个唯一的bean对象注入!
- @Resource
放在属性上,起别名@Resource(name = “别名”),
5.3.3.1 开发方式一@Autowired
使用Autowired 我们可以不用编写Set方法了,前提是你这个自动装配的属性在 IOC(Spring)容器中存在,且符合名字byname!
- 导入约束 : context约束
xmlns:context=“http://www.springframework.org/schema/context”
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd"> - 配置注解的支持 :context:annotation-config/ 【重要!】
1 配置文件约束
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<bean class="com.lala.pojo.Cat"></bean>
<bean class="com.lala.pojo.Dog"></bean>
<bean id="animal" class="com.lala.pojo.Animal"></bean>
</beans>
== @Autowired装配的思想就是byType,class唯一,所以删掉id也可以使用==
2 Animal
public class Animal implements Serializable {
@Autowired
private String name;
@Autowired
private Cat cat;
private Dog dog;
public Animal(){
}
}
@Autowired也可以放在set的上面
测试
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("base.xml");
Animal animal = (Animal) context.getBean("animal",Animal.class);
animal.getCat().voice();
animal.getDog().voice();
5.3.3.1 开发方式二 @Resource
1.xml
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<bean class="com.lala.pojo.Cat"></bean>
<bean class="com.lala.pojo.Dog"></bean>
<bean id="animal" class="com.lala.pojo.Animal"></bean>
</beans>
2 Animal
public class Animal implements Serializable {
@Resource
private String name;
@Resource
private Cat cat;
private Dog dog;
public Animal(){
}
}
注意:@Resource(name = “dog”)中的name对应的是xml中的bean id
3 测试
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("base.xml");
Animal animal = (Animal) context.getBean("animal",Animal.class);
animal.getCat().voice();
animal.getDog().voice();
小结:
@Resource 和@ Autowired 的区别:
- 都是用来自动装配的,都可以放在属性字段上
- @ Autowired 通过byType的方式实现,而且必须要求这个对象存在! 【常用】
- @ Resource 默认通过byname的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错! 【常用】
- 执行顺序不同:@ Autowired 通过byType的方式实现。@ Resource 默认通过byname的方式实现。
5.3.5 多的注解装配
- 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"
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/>
<!--扫描该包下的所有的注解都会生效-->
<context:component-scan base-package="com.lala"/>
</beans>
- student
@Component
public class Student implements Serializable {
@Value("18")
private int age;
@Value("王五")
private String name;
}
@Component表示该类已经被Spring托管了
@value可以理解为原来的xml中的bean中属性注入属性
5.3.6 完全java注解开发
我们现在要完全不使用Spring的xml配置了,全权交给Java来做!
JavaConfig 是Spring的一个子项目,在Spring 4 之后,它成为了一个核心功能!
Student
//这里这个注解的意思,就是说明这个类被Spring接管了,注册到了容器中
@Component
public class Student implements Serializable {
@Value("18")
private int age;
@Value("王五")
private String name;
配置类
@Configuration
//@Configuration 表示该类是个配置类,其实本身就是一个组件
@ComponentScan(value ="com.g.pojo")
//@ComponentScan 扫描该包下的组件
public class BeanConfig {
@Bean
//注册一个bean,相当于我们之前的写的bean标签
//定义的方法名相当于bean中的id的值
//返回值的类型类相当于bean标签中的calss的值
public Student student(){
return new Student();
}
}
测试类
public class MyTest {
public static void main(String[] args) {
//如果完全使用了配置类方式去做,我们就只能通过 AnnotationConfig 上下文来获取容器,通过配置类的class对象加载!
ApplicationContext context = new AnnotationConfigApplicationContext(KuangConfig.class);
User getUser = (User) context.getBean("user");
System.out.println(getUser.getName());
}
}