1、Spring
1.1、简介
-
Spring:春天 ----->给软件行业带来了春天
-
2002,首次推出了Spring框架的雏形:interface21框架
-
Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版。
-
Rod Johnson,Spring Framework创始人,著名作者。悉尼大学的音乐学博士。
-
spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架
-
SSH : Struct2 + Spring + Hibernate
-
SSM:SpringMVC + Spring + Mybatis
官方下载地址:JFrog
Github: GitHub - spring-projects/spring-framework: Spring Framework
<!-- https://mvnrepository.com/artifact/org.springframework/spring-web --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.2.0.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.0.RELEASE</version> </dependency>
1.2、优点
-
Spring是一个开源的免费的框架(容器)
-
Spring是一个轻量级的、非入侵式的框架
-
控制反转(IOC),面向切面编程(AOP)
-
支持事务的处理,对框架整合的支持
总结一句话:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架
1.3、组成
1.4、拓展
-
Spring Boot
-
一个快速开发的脚手架
-
基于SpringBoot可以快速的开发单个微服务
-
约定大于配置
-
-
Spring Cloud
-
SpringCloud是基于SpringBoot实现的
-
因为现在大多数的公司都在使用SpringBoot进行快速开发、学习SpringBoot的前提,需要完全掌握Spring及SpringMVC
承上启下的作用
2、 IOC理论推导
下面是没有用到 IOC容器之前,我们原始的方式:
-
UserDao 接口类
public interface UserDao { public void getUser(); }
-
UserDaoImpl实现类
public class UserDaoImpl implements UserDao { @Override public void getUser(){ System.out.println("获取用户数据!"); } }
-
UserService 业务接口
public interface UserService { public void getUser(); }
-
UserServiceImpl 业务实现类
public class UserServiceImpl implements UserService { private UserDao = new UserDaoImpl(); @Override public void getUser() { userDao.getUser(); } }
-
测试类
@Test public void test() { UserService service = new UserServiceImpl(); service.getUser(); }
在外面之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改源代码。如果程序代码量十分大,
修改一次的成本代价十分昂贵!
现在我们来修改一下代码,来体会一下解耦合的操作:
-
我们使用一个Set接口实现
public class UserServiceImpl implements UserService { private UserDao userDao; //利用set进行动态实现值的注入 public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void getUser() { userDao.getUser(); } }
-
测试类中的修改
@Test public void test () { UserServiceImpl service = new UserServiceImpl(); service.setUserDao(new UserDaoMySqlImpl()); service.getUser(); service.setUserDao(new UserDaoOracleImpl()); service.getUser(); }
思考:
我们原始的方法和上面的方法已经发生了根本性的变化:
-
之前,所有东西都是由程序主动创建对象,控制权在程序员手上
-
现在,使用了set注入之后,程序不再具有主动性,而是变成了被动的接受对象,把主动权交给了调用者
这种思想,从本质上解决了问题,我们程序员不用再去管理对象的创建了。系统的耦合性大大降低,可以更加专注的在业务的实现上!
这就是IOC的原型。
3、IOC本质
控制反转IOC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IOC的一种方法,也有人认为DI只是IOC的另一种说法。
没有IOC的程序中,我们使用面向对象编程,对象的创建与对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,
控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
IOC是Spring框架的核心内容,使用多种方式完美的实现了IOC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IOC。
Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从IOC容器中取出需要的对象。
采用XML方式配置Bean的时候,Bean的定义信息和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在
实体类中,从而达到了零配置的目的。
控制反转是一种通过描述(xml或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IOC容器,其实现方法是依赖注入
(Dependency Injection,DI)。
4、编写第一个Spring代码(Hello Spring)
-
编写一个Hello实体类
public class Hello { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public void show() { System.out.println("Hello" + name); } }
-
编写我们的Spring文件,命名为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就是java对象,由Spring创建和管理--> <bean id = "hello" class = "com.shelby.pojo.Hello"> <property name = "name" value = "Spring" /> </bean> </beans>
-
测试类
@Test public void test() { //解析beans.xml文件,生成管理相应的Bean对象。 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); //getBean :参数即为Spring配置文件中的bean的id。 Hello hello = context.getBean("hello") hello.show(); }
这个过程就叫控制反转:
控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring后,对象是由Spring来创建的。
反转:程序本身不创建对象,而变成被动的接受对象。
依赖注入:就是利用set方法进行注入的。
IOC是一种编程思想,由主动的编程变成被动的接受
可以通过new ClassPathXmlApplicationContext去浏览一下底层源码。
到了现在,我们彻底不用再程序中改动了,要实现不同的操作,只需要在xml配置文件中进行修改。
所谓的IOC,一句话搞定:对象由Spring来创建,管理,装配
5、IOC创建对象的方式
-
使用无参构造创建对象 【默认】
-
使用有参构造创建对象
-
下标赋值
<bean id="user" class="com.shelby.pojo.user"> <constructor-arg index="0" value="小傻子学java" /> </bean>
-
类型 【不建议使用】
<bean id="user" class="com.shelby.pojo.user"> <constructor-arg type="java.lang.String" value="小傻子学java" /> </bean>
-
参数名
<bean id="user" class="com.shelby.pojo.user"> <constructor-arg name="name" value="小傻子学java" /> </bean>
-
总结:在配置文件加载的时候,容器中管理的对象就已经初始化了!
6、Spring配置
6.1、别名
-
如果添加了别名,我们也可以使用别名获取到这个对象
<alias name="user" alias="userNew" />
6.2Bean的配置
-
id :bean的唯一标识符,也就是相当于我们学的对象名
-
class :bean对象所对应的全限定名:包名 + 类型
-
name :也是别名,name可以取多个别名(比alias高级)
<bean id="user" class="com.shelby.pojo.user" name="userNew" />
6.3、import
-
import,一般用于团队开发使用,可以将多个配置文件,导入合并为一个
-
applicationContext.xml
-
<import resource="xxx.xml"/>
使用的时候,直接使用总的配置就可以了。
7、依赖注入
7.1、构造器注入
【见第五章-第2点】
7.2、Set方式注入 【重点】
-
依赖注入:Set注入
-
依赖:bean对象的创建依赖于容器
-
注入:bean对象中的所有属性,由容器来注入!
-
【模拟Demo】
-
复杂类型
//定义一个Address的实体类 package com.shelby.pojo; public class Address { private String addr; public String getAddr() { return addr; } public void setAddr(String addr) { this.addr = addr; } }
-
真实测试对象
//定义一个Student的实体类 package com.shelby.pojo; import java.util.*; public class Student { private String name; private Address addr; private String[] books; private List<String> hobbies; private Map<String, String> card; private Set<String> games; private String wife; private Properties info; public String getName() { return name; } public void setName(String name) { this.name = name; } public Address getAddr() { return addr; } public void setAddr(Address addr) { this.addr = addr; } public String[] getBooks() { return books; } public void setBooks(String[] books) { this.books = books; } public List<String> getHobbies() { return hobbies; } public void setHobbies(List<String> hobbies) { this.hobbies = hobbies; } public Map<String, String> getCard() { return card; } public void setCard(Map<String, String> card) { this.card = card; } public Set<String> getGames() { return games; } public void setGames(Set<String> games) { this.games = games; } public String getWife() { return wife; } public void setWife(String wife) { this.wife = wife; } public Properties getInfo() { return info; } public void setInfo(Properties info) { this.info = info; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", addr=" + addr + ", books=" + Arrays.toString(books) + ", hobbies=" + hobbies + ", card=" + card + ", games=" + games + ", wife='" + wife + '\'' + ", info=" + info + '}'; } }
3.applicationContext.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="address" class="com.shelby.pojo.Address" > <property name="address" value="上海"/> </bean> <!--普通值注入,直接使用value--> <bean id="student" class="com.shelby.pojo.Student"> <property name="name" value="小傻子学java"/> <!--Bean注入,使用ref--> <property name="address" ref="address"/> <!--数组注入--> <property name="books"> <array> <value>红楼梦</value> <value>三国演义</value> </array> </property> <!--List注入--> <property name="hobbies"> <list> <value>写代码</value> <value>唱歌</value> </list> </property> <!--Map注入--> <property name="card"> <map> <entry key="身份证" value="333333222222221111"/> </map> </property> <!--Set注入--> <property name="games"> <set> <value>LOL</value> <value>COC</value> </set> </property> <!--null注入--> <!--<property name="wife" value="">--> <property name="wife"> <null/> </property> <!--Properties注入--> <property name="info"> <props> <prop key="学号">1001</prop> <prop key="性别">男</prop> </props> </property> </bean> </beans>
4.测试类
//测试类 @Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Student stu = (Student)context.getBean("student"); System.out.println(stu.toStirng()); }
7.3、拓展方式注入
-
p(property)命名空间注入,可以直接使用p:属性名来注入属性的值
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="student" class="cm.shelby.pojo.Student" p:name="小傻子学java"/> </beans>
-
c(constructor-args)命名空间注入,通过构造器注入
-
使用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:p="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="cm.shelby.pojo.Student" c:name="小傻子学java"/> </beans>
注意点:使用p命名空间和c命名空间需要导入相应的约束!
7.4bean的作用域
-
单例模式【Spring默认机制】
<bean id="student" class="cm.shelby.pojo.Student" p:name="小傻子学java" scope="singleton"/>
-
原型模式:每次从容器中getBean()的时候,都会产生一个新对象
<bean id="student" class="cm.shelby.pojo.Student" p:name="小傻子学java" scope="prototype"/>
-
其余的request、session、application这三个只能在web开发中使用到。
8、Bean的自动装配
-
自动装配是Spring满足bean依赖的一种方式
-
Spring会在上下文中自当寻找,并自动给bean装配属性
在Spring中有三种装配方式
-
在xml中显示的配置
-
在java中显示的配置
-
隐式的自动装配bean【重要】
8.1测试
-
测试代码
-
一个人有两个不同的宠物(Person类、Dog类、Cat类)
-
//测试类 @Test public void test() { ApplicationContext context = new ClassPathXmlApplicationContext("application.xml"); Person person = context.getBean("person",Person.class); person.getDog.shout(); person.getCat.shout(); }
8.2ByName自动装配
-
byName: 会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanid。
<bean id="cat" class="com.shelby.pojo.Cat"/> <bean id="dog" class="com.shelby.pojo.Dog"/> <bean id="person" class="com.shelby.pojo.Person" autowire="byName"> <property name="name" value="小傻子学java"/> </bean>
8.3ByType自动装配
-
byType: 会自动在容器上下文中查找,和自己对象属性类型相同的bean。
-
byType把bean中的id去掉,一样可以正常拿到对象,只要确保bean中class的类型唯一且能对应上就可以
-
<bean id="cat" class="com.shelby.pojo.Cat"/> <bean id="dog" class="com.shelby.pojo.Dog"/> <bean id="person" class="com.shelby.pojo.Person" autowire="byType"> <property name="name" value="小傻子学java"/> </bean>
总结:
-
byname的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的setXxx方法的Xxx值一致。
-
bytype的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致。
8.4使用注解的自动装配
-
jdk1.5开始支持的注解,Spring从2.5就开始支持注解了
-
The introduction of annotation-based configuration raised the question of whether this approach is “better” than XML. (摘自Spring官网)
使用注解的步骤:
-
导入约束
<?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/>
-
@Autowired
-
直接在属性上使用。
-
也可以在set方法上使用。
-
使用Autowired我们可以不用编写set方法了,前提是自动装配的这个属性在IOC(Spring)容器照顾你存在,且符合名字byName。
-
科普:
@Nullable //字段标记了这个注解,说明这个字段可以为null //构造器 public Person(@Nullable String name) { this.name = name; }
public @interface Autowired { boolean required() default true; }
//实体类中的一个复杂属性 //如果我们显示定义了Autowired的required属性值为false,说明这个对象可以为null,否则不允许为空! @Atuowired(required = false) private Cat cat;
-
@Qualifier
<bean id="dog1" class="com.shelby.pojo.Dog"/> <bean id="dog2" class="com.shelby.pojo.Dog"/>
@Autowired @Qualifier(value="dog1")//如果applicationContext文件中有多个类型相同的bean,可以使用Qualifier来指定使用哪一个bean private Dog dog;
注:@Qualifier一般和@Autowired搭配起来使用
如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成时,我们可以使用@Qualifier(value="xxx")去配合@Autowired使用,指定一个唯一的bean对象注入!
@ 附件:Spring所需要的依赖及xml文件
-
使用Spring所需要导入的依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-web --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.2.0.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.0.RELEASE</version> </dependency>
-
ApplicationContext.xml模板【Spring官网有】
<?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="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> </beans>
3.p命名空间约束
xmlns:p="http://www.springframework.org/schema/p"
4.c命名空间约束
xmlns:p="http://www.springframework.org/schema/c"