一、简介
经典的三层框架诞生SSH (Strut2+Spring+Hibernate),新三大框架诞生,SSM(SpringMVC+Spring+MyBatis),SpringBoot+SpringCloud 微服务
二、spring框架
安装地址:http://spring.io
1、框架组成
Spring是一个开源框架,是为了解决企业应用程序开发复杂性而创建的。
Spring 框架是一个分层架构,由7个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式,如下图所示:
组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现
每个模块的功能如下:
Spring 框架的功能可以用在任何J2EE服务器中,大多数功能也适用于不受管理的环境。Spring 的核心要点是:支持不绑定到特定J2EE服务的可重用业务和数据访问对象。毫无疑问,这样的对象可以在不同J2EE环境(Web或EJB)、独立应用程序、测试环境之间重用。
Spring以一种非侵入式的方式来管理你的代码,Spring提倡"最少侵入",这也就意味着你可以适当的时候安装或卸载Spring ,但这点越来越模糊。
2、核心概念
3、三大核心组件的关系
Bean、Context、Core三大核心组件的关系:
Bean 包装的是 Object,而 Object 必然有数据,如何给这些数据提供生存环境就是 Context要解决的问题。bean的作用域:singleton表示一个bean定义对应一个实例。 prototype表示一个bean定义对应多个实例。 singleton是缺省值。在设计bean时,依据实际业务的需要,可以为bean提供相应的生命周期方法,比如在初始化方法当中完成资源加载等类似的逻辑,在销毁方法中释放资源。因此bean当中是否有生命周期相关的方法,完成取决于实际业务需要,并不是必须的.
对 Context 来说它就是要发现每个 Bean 之间的关系,为它们建立这种关系并且要维护好这种关系。所以 Context 就是一个Bean关系的集合,这个关系集合又叫 Ioc 容器,一旦建立起这个 Ioc 容器后 Spring 就可以为你工作了。
Core 就是发现、建立和维护每个 Bean 之间的关系所需要的一些类的工具,从这个角度看来,Core 这个组件叫 Util 更能让你理解。
把Bean 比作一场演出中的演员的话,那 Context 就是这场演出的舞台背景,而 Core应该就是演出的道具了。只有他们在一起才能具备能演出一场好戏的最基本的条件。当然有最基本的条件还不能使这场演出脱颖而出,还要他表演的节目足够的精彩,这些节目就是 Spring 能提供的特色功能。
4、Spring框架两大核心:IoC和DI
1)IoC(Inversion of Control)简单来说就是将对象Object的创建的权力及对象的生命周期的管理过程交由Spring框架来处理,从此在开发过程中不在需要关注对象的创建和生命周期的管理,而是在需要的时候由Spring框架提供,这个由Spring框架管理对象创建和生命周期的机制称之为控制反转。对象只是被动的接收依赖对象。
2)在创建对象的过程中Spring可以依据对象的关系,自动把其它对象注入(无需创建对象,直接拿着使用)进来,这个过程称之为DI(Dependency Injection)依赖注入。
3)总结下Spring核心就干了两件事:
创建对象
设置对象的关联关系
4.1、IOC解释
IOC(Inversion of Control),控制反转。是把管理对象的权利交给spring框架。
ioc的过程就是创建对象的过程(new对象)
就是指将对象的创建,对象的存储(map),对象的管理(依赖查找,依赖注入)都交给了spring容器。
两种方式:xml方式实现ioc、注解方式实现ioc
4.2、DI解释
相对于IoC而言,依赖注入(DI)更加准确地描述了IoC的设计理念。所谓依赖注入,即组件之间的依赖关系由容器在应用系统运行期来决定,也就是由容器动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。
IOC具有三种注入方式,分别是构造函数注入、属性注入和接口注入。
三、实现IOC的两种方式
1、XML的方式实现IOC的步骤
该方式了解即可
1.1、创建类
package cn.tedu.spring;
public class Hello {
void hi(){
System.out.println("hello spring ioc~ ");
}
}
1.2、创建配置文件,配置类的信息
选中resources-右键-new-xml config…-spring config-输入文件名-回车
<?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">
<!-- 配置一个类的信息 id是bean的唯一标识 class是类的全路径,找到类名copy reference粘贴过来即可-->
<bean id="hello" class="cn.tedu.spring.Hello"></bean>
</beans>
1.3、读取配置文件,直接获取对象
package cn.tedu.test;
import org.junit.jupiter.api.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestIOC {
//单元测试junit方法:@Test public void 没有参数
@Test
public void ioc(){
//1.读取配置文件--参数是文件的路径
ClassPathXmlApplicationContext spring =
/*配置文件名也要一致,否则报错*/
new ClassPathXmlApplicationContext("spring-config.xml");
//2.获取对象--参数是配置文件里bean的id属性值
//属性值大小写一定要一致,否则找不到,报错
Object o = spring.getBean("hello");
//打印地址值
System.out.println(o);//cn.tedu.spring.Hello@302552ec
//o.hi();父类不能使用子类的特有功能
//解决办法:向下造型,专门使用子类的资源
Hello h = (Hello) o ;
//默认的权限修饰符的方法不能被调用,要改为public才行
h.hi();
}
}
1.4、总结
2、注解方式实现IOC
哪个类想让spring框架new对象,就在类上使用注解:@Component / @Service / @Controller 使用其中一个就可以
2.1、创建类,使用注解
package cn.tedu.spring2;
import org.springframework.stereotype.Component;
//Map<类名首字母要小写,类的对象> - {user=new User()}
@Component
public class User {
public void get(){
System.out.println("hello springioc");
}
}
2.2、创建配置文件,扫描包,只需要指定包的路径
<?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">
<!-- 包扫描:只需要指定从哪个包开始扫描,
用了@Component注解的类,自动ioc
base-package需要指定一个包的路径
-->
<context:component-scan base-package="cn.tedu.spring2"></context:component-scan>
</beans>
2.3读取配置文件,获取对象,调用方法
配置文件可以有多个,也可以在一个配置文件操作
package cn.tedu.test;
import org.junit.jupiter.api.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
//测试 注解开发
public class TestIOC2 {
@Test
public void ioc2(){
//1,读取核心配置文件
ClassPathXmlApplicationContext spring =
new ClassPathXmlApplicationContext(
"spring-config2.xml");
//2,getBean -- 参数是类名,但是首字母要变成小写才行
Object o = spring.getBean("user");
System.out.println(o);//cn.tedu.spring2.User@37d4349f
Object o2 = spring.getBean("userInfo");
System.out.println(o2);//cn.tedu.spring2.UserInfo@2805d709
}
}
2.4、总结
3、注解方式实现不同包下多个类的 IOC
1)创建多个不同的包名,分别创建各自的类
包名:cn.tedu.spring---Hello类--创建hi()方法
包名:cn.tedu.annocation---User类和UserInfo类--创建get()方法和eat()方法
注意:所有的类上都要加注解@Component
2)配置文件
resources-->spring-Config2.xml
3)测试读取配置文件,获取对象,调用方法
package cn.tedu.test;
import cn.tedu.annotation.User;
import cn.tedu.annotation.UserInfo;
import cn.tedu.spring.Hello;
import org.junit.jupiter.api.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAll {
@Test
public void ioc(){
//1.读取配置文件
ClassPathXmlApplicationContext spring =
new ClassPathXmlApplicationContext(
"spring-Config2.xml");
//2.通过map<k,v>中的k值,即类名获取对应的对象(全路径名)
Object o1 = spring.getBean("hello");
System.out.println(o1);//打印地址值
//3.向下造型获取指定对象的方法
Hello hello = (Hello)o1;
hello.hi();//调用方法
Object o2 = spring.getBean("user");
System.out.println(o2);
User user = (User) o2;
user.get();
Object o3 = spring.getBean("userInfo");
System.out.println(o3);
UserInfo userInfo = (UserInfo) o3;
userInfo.eat();
}
}
四、模拟IOC
1、创建Bean类,描述类的信息
package cn.tedu.myioc;
//描述一个类的信息,spring把每个类当做一个bean
public class Bean {
private String beanName;//类的名字
private String beanPath;//类的全路径
//提供构造方法constructors
public Bean(){}
public Bean(String beanName, String beanPath) {
this.beanName = beanName;
this.beanPath = beanPath;
}
//get set tostring
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public String getBeanPath() {
return beanPath;
}
public void setBeanPath(String beanPath) {
this.beanPath = beanPath;
}
@Override
public String toString() {
return "Bean{" +
"beanName='" + beanName + '\'' +
", beanPath='" + beanPath + '\'' +
'}';
}
}
/**或者使用Lombok*/
package cn.tedu.design;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/*Lombok插件省略set、get、tostring()*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Bean {
private String name;
private String path;
}
2、创建Spring容器,并指定要维护的类,提供getBean(),根据beanName获取对象
package cn.tedu.myioc;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MyIOC {
//1,创建list,存好多bean,有序有下表
private List<Bean> beans = new ArrayList<>();
public MyIOC() throws Exception {
Bean b1 = new Bean("hello","cn.tedu.myioc.Hello");
Bean b2 = new Bean("user","cn.tedu.myioc.User");
beans.add(b1);//把指定对象添加到beans集合
beans.add(b2);
init();//自定义方法--用于反射遍历,创建全路径对象
}
//准备spring容器Map<k,v>,特点:无序无下标不可重复,唯一性
//Map<String,Object> map = new HashMap<>();
Map<String,Object> map = new ConcurrentHashMap<>
//2,创建map,存对象 { hello=new Hello() , user=new User()}
public void init() throws Exception {
//遍历list,获取每个bean
for(Bean b : beans){
String key = b.getBeanName();
String quanlujing = b.getBeanPath();
Object value = Class.forName(quanlujing).newInstance();
map.put(key,value);
//map键值对不够安全,多线程抢占时并发所以把HashMap<>转为ConcurrentHashMap<>
}
}
//3,getBean()--根据key获取value
public Object getBean(String beanname){
return map.get(beanname) ;
}
}
3、创建指定的Hello、User类
4、创建测试类
package cn.tedu.test;
import cn.tedu.design.User;
import cn.tedu.design.Hello;
import cn.tedu.design.SpringContext;
public class TestMyIOC {
public static void main(String[] args) throws Exception {
SpringContext spring = new SpringContext();
Hello h = (Hello)spring.getBean("hello");
System.out.println(h);//获取地址值
o.get();//如果类里有方法可以进行调用
User user = (User) spring.getBean("user");
System.out.println(user);
user.find();
}
}
5,总结
五、DI依赖注入
1、概述
依赖注入,前提是先使用注解@Component完成IOC
使用DI注解@Autowired ,使两个类(对象)之间建立关系
2、不使用DI使两个类建立关系的方法
2.1、创建Maven工程module
创建Dept类
package cn.tedu.pojo;
import org.springframework.stereotype.Component;
@Component//交给spring进行ioc
public class Dept {
public String name = "java研发部门";
@Override
public String toString() {
return "Dept{" +
"name='" + name + '\'' +
'}';
}
}
创建User类
package cn.tedu.pojo;
import org.springframework.stereotype.Component;
@Component//交给spring进行ioc
public class User {
String name = "蔡徐坤";
//描述User类和Dept类的关系
private Dept d;
public void setD(Dept d) {
this.d = d;
}
public Dept getD() {
return d;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", d=" + d +
'}';
}
}
测试
package cn.tedu.di;
import cn.tedu.pojo.Dept;
import cn.tedu.pojo.User;
public class Test1 {
public static void main(String[] args) {
User u = new User();
//先设置部门信息,否则永远获取的是null
u.setD(new Dept());
//获取用户的部门信息
Dept dept = u.getD();
//获取部门名称
System.out.println(dept.name);
}
}
3、使用SpringDI依赖注入时的步骤
3.1、创建Teacher类
package cn.tedu.vo;
import org.springframework.stereotype.Component;
@Component//ioc
public class Teacher {
public String name = "jack" ;
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
'}';
}
}
3.2、创建Student类
两个类建立关系,DI提供注解@Autowired
package cn.tedu.vo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component//ioc
public class Student {
public String name = "蔡徐坤" ;
// 表示两个类之间的关系
@Autowired//DI依赖注入,自动装配,自动布线
Teacher t ;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", t=" + t +
'}';
}
}
3.3 创建核心配置文件,配置包扫描的路径
<?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">
<!--包扫描:扫描指定包路径下的所有类
哪些类有@Component注解,就帮哪些类new-ioc
-->
<context:component-scan base-package="cn.tedu.vo"></context:component-scan>
</beans>
3.4测试,读取配置文件,向下造型回去子类的属性和功能
package cn.tedu.di;
import cn.tedu.vo.Student;
import cn.tedu.vo.Teacher;
import org.springframework.context.support.ClassPathXmlApplicationContext;
//测试springdi
public class Test2 {
public static void main(String[] args) {
//1,读取核心配置文件
ClassPathXmlApplicationContext spring =
new ClassPathXmlApplicationContext(
"spring-config.xml");
//2,根据类名,获取对象
//右侧返回的是Object父类,左侧要子类--需要强转--向下转型--是为了使用子类的功能
Teacher t = (Teacher) spring.getBean("teacher");
System.out.println(t);//Teacher{name='jack'}
Student s = (Student) spring.getBean("student");
//DI:在获取学生信息的同时,也获取到了关联的老师信息
System.out.println(s);//Student{name='蔡徐坤', t=Teacher{name='jack'}}
}
}
3.5、总结