Spring学习
1. Spring
1.1 简介
- 2002年首次推出了spring雏形 interface21
- spring框架即以interface21框架为基础经过重新设计,不断丰富内涵,于2004年3月24日发布了1.0正式版本
- spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架
- SSH: Struct2 + Spring + Hibernate
- SSM: SpringMVC + Spring + Mybatis
官网:https://spring.io/projects/spring-framework#learn 下载:https://repo.spring.io/release/org/springframework/spring/ 导包:
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.7</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
1.2 优点
- 开源、免费容器
- 轻量级、非入侵式框架
- 控制反转(IOC), 面向切面编程(AOP)
- 支持事务处理,对框架整合的支持
** 总结一句话:Spring就是一个轻量级的控制反转(IOC)和面向切面编程的容器**
1.3 组成
- 核心容器(Spring Core)
核心容器提供Spring框架的基本功能。Spring以bean的方式组织和管理Java应用中的各个组件及其关系。Spring使用BeanFactory来产生和管理Bean,它是工厂模式的实现。BeanFactory使用控制反转(IoC)模式将应用的配置和依赖性规范与实际的应用程序代码分开。
- 应用上下文(Spring Context)
Spring上下文是一个配置文件,向Spring框架提供上下文信息。Spring上下文包括企业服务,如JNDI、EJB、电子邮件、国际化、校验和调度功能。
- Spring面向切面编程(Spring AOP)
通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring框架中。所以,可以很容易地使 Spring框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
- JDBC和DAO模块(Spring DAO)
JDBC、DAO的抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理,和不同数据库供应商所抛出的错误信息。异常层次结构简化了错误处理,并且极大的降低了需要编写的代码数量,比如打开和关闭链接。
- 对象实体映射(Spring ORM)
Spring框架插入了若干个ORM框架,从而提供了ORM对象的关系工具,其中包括了Hibernate、JDO和 IBatis SQL Map等,所有这些都遵从Spring的通用事物和DAO异常层次结构。
- Web模块(Spring Web)
Web上下文模块建立在应用程序上下文模块之上,为基于web的应用程序提供了上下文。所以Spring框架支持与Struts集成,web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
- MVC模块(Spring Web MVC)
MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架变成为高度可配置的。MVC容纳了大量视图技术,其中包括JSP、POI等,模型来有JavaBean来构成,存放于m当中,而视图是一个街口,负责实现模型,控制器表示逻辑代码,由c的事情。Spring框架的功能可以用在任何J2EE服务器当中,大多数功能也适用于不受管理的环境。Spring的核心要点就是支持不绑定到特定J2EE服务的可重用业务和数据的访问的对象,毫无疑问这样的对象可以在不同的J2EE环境,独立应用程序和测试环境之间重用。
1.4 拓展
在Spring官网介绍:现代化的java开发
- Spring Boot
- 一个快速开发的脚手架
- 基于Spring boot可以快速的开发单个微服务
- 约定大于配置
- Spring Cloud
- Spring Cloud是基于SpringBoot实现的
学习SpringBoot前提是学会Spring和SpringMVC 弊端:发展太久,违背了原来的理念,配置繁琐(后来出现了SpringBoot)
2. IOC理论推导
- UserDao接口
- UserDaoMapper实现类(UserDaoImpl)
- UserService 业务接口
- UserServiceImpl业务实现类
之前与用户对接的业务层变化不大,而Dao层经常因为业务变动,添加一个实现类,修改一次成本十分昂贵 通过添加setUserDao接口,发生了革命性变化
//利用set进行动态实现值的注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
- 之前,程序是主动创建对象,控制权在程序员手上
- 使用set注入后,程序不再具有主动性,而是变成了被动接受对象
这种思想 , 从本质上解决了问题 , 我们程序员不再去管理对象的创建了 , 更多的去关注业务的实现 . 耦合性大大降低 . 这也就是IOC的原型 !
3. HelloSpring
4. IOC创建对象的方式
xml配置文件读取完成,ioc就已经完成了对象创建
5.Spring配置
5.1 别名
<bean id="user2" class="com.junyipan.pojo.User2">
<constructor-arg name="name" value="测试"/>
</bean>
<alias name="user2" alias="sdfawaefwaew"/>
static ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
@Test
// 有参构造
public void initUser2(){
User2 user2 = (User2) context.getBean("sdfawaefwaew");
user2.show();
}
5.2 Bean配置
<!-- id: bean唯一标志符-->
<!-- class:bean对象所对应的全限定名:包名+类型-->
<!-- name:也是别名,而且name可以同时取多个别名,分隔符可以同时用,;-->
<bean id="user2" class="com.junyipan.pojo.User2" name="user22,dsfwe;ewfew aaaa">
<constructor-arg name="name" value="测试"/>
</bean>
5.3 import
import一般用于团队开发,可以将多个配置文件,导入合并为一个
例如有beans1.xml, beans2.xml, beans3.xml,最后在一个ApplicationContext.xml文件中用import解决 注意:同名id的bean会被覆盖
6. 依赖注入(DI)
bean | ref | idref | list | set | map | props | value | null
6.1 构造器注入
c命名空间注入
6.2 set方式注入【重点】
p命名空间注入就是使用的set方式注入
- 依赖注入:set注入
- 依赖:bean对象创建依赖于容器
- 注入:bean对象所有属性由容器来注入
【环境搭建】 1. 复杂类型
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;
}
2. 真实测试对象
3. 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 id="student" class="com.junyipan.pojo.Student">
<!-- 第一种,普通值注入-->
<property name="name" value="熊仔"/>
</bean>
<!-- more bean definitions go here -->
</beans>
4. 测试类
import com.junyipan.pojo.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// Student student = (Student) context.getBean("student");
Student student = context.getBean(Student.class);
System.out.println(student);
}
}
6.3 拓展方式注入
我们可以用p命名空间和c命名空间注入
1. 声明pojo
package com.junyipan.pojo;
public class User {
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
2.使用
<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"
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">
<!-- p命名空间注入,可以直接注入属性的值(set) p命名空间即property命名空间-->
<bean id="user" class="com.junyipan.pojo.User" p:age="18" p:name="熊仔"/>
<!-- c命名空间注入,通过构造器注入:constructor-args-->
<bean id="user2" class="com.junyipan.pojo.User" c:age="18" c:name="熊仔2" />
</beans>
3.测试
@Test // p命名空间注入
public void test02(){
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user = context.getBean("user", User.class);
System.out.println(user);
}
@Test // c命名空间注入
public void test03(){
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user = context.getBean("user2", User.class);
System.out.println(user);
}
** 注意点:p命名和c命名空间不能直接使用,需要在xml的header中导入p约束和c约束**
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
6.4 bean的作用域
在
bean
中定义属性scope,默认是singleton单例模式,还有prototype原型模式,session模式, request模式
- 单例模式
<bean id="user2" class="com.junyipan.pojo.User" c:age="18" c:name="熊仔2" scope="singleton"/>
- 原型模式:每次从容器中get时候,都会生成一个新对象
<bean id="user4" class="com.junyipan.pojo.User" c:age="18" c:name="熊仔4" scope="prototype"/>
- 其余的request,session,application都只能在web开发中才能用到
7. bean的自动装配
- 自动装配式spring满足bean依赖的一种方式
- spring会在上下文中自动寻找,并自动给bean装配
在spring中有三种装配方式:
- 在xml中显式装配
- 在java中显式装配
- 隐式自动装配bean【重要】
7.1 测试
- 环境搭建
- person,一个人有2个宠物
public class Person {
private Cat cat;
private Dog dog;
private String name;
}
7.2 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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="cat" class="com.junyipan.pojo.Cat"/>
<bean id="dog" class="com.junyipan.pojo.Dog"/>
<bean id="person" class="com.junyipan.pojo.Person">
<property name="name" value="俊逸"/>
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
</bean>
<!-- more bean definitions go here -->
<bean id="person2" class="com.junyipan.pojo.Person" autowire="byName">
</bean>
</beans>
7.3 byType
<?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="cat" class="com.junyipan.pojo.Cat"/>
<bean id="dog222" class="com.junyipan.pojo.Dog"/>
<bean id="person" class="com.junyipan.pojo.Person">
<property name="name" value="俊逸"/>
<property name="cat" ref="cat"/>
<property name="dog" ref="dog222"/>
</bean>
<!-- more bean definitions go here -->
<bean id="person2" class="com.junyipan.pojo.Person" autowire="byType">
</bean>
</beans>
- byName会自动再容器上下文中查找和自己对象set方法后面的值相同的bean id
- byType会自动再容器上下文中查找和自己对象set方法后面的类型相同的bean id
小结:
- byName需要保证所有bean的id唯一,会自动再容器上下文中查找,且这个bean需要和自动注入的属性对应的set方法的值一致
- byType需要保证所有bean的class唯一,会自动再容器上下文中查找,且这个bean需要和自动注入的属性的类型一致
7.4 使用注解实现自动装配
jdk1.5支持的注解,Spring2.5就支持注解了
要使用注解须知:
- 导入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
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/>
</beans>
@Autowired
- 直接在属性上使用即可,也可以在set方法上使用
- 优先按类型自动装配,如果找不到就报错,找到多个则按名字匹配,还是找不到就报错
- 使用之后,不需要再写set方法了,前提是自动装配的属性在IOC容器中存在,且符合byType + byName
- 如果@Autowired(required=true)中的required(默认为true)显式定义了为false,则代表该属性值可以为null,否则不可为null。 required=false也可以通过@Nullable实现相同效果
- 如果@Autowired自动装配的环境比较复杂,无法通过一个注解完成时,可以使用@Qualifier(value="xxx")来配合使用指定一个唯一的对象
- @Resource或@Resource(name="xxx")和@Autowired是一样的效果
小结: @Autowired和@Resource区别:
- 都是用来自动装配的,都可以放在属性字段上
- @Autowired优先通过byType方式装配,如果找不到报错,找到多个则byName区别
- @Resource默认通过byName方式实现,如果找不到,则通过byType
8. 使用注解开发
在spring4之后,要使用注解开发,必须要保证aop包导入成功 使用注解需要导入context约束,注解支持
8.1 注解说明
-
@Autowired: 自动装配通过类型、名字 如果Autowired通过类型取出的不是唯一,则再通过名称匹配,也可以通过@Qualifier(value="xxxx")显式指定装配
-
@Nullable:字段标记了这个注解,说明这个字段可以为null
-
@Resource:自动装配通过名字、类型
-
@Component: 组件,放在类上面,说明这个类被spring管理了,就是bean。
相当于在applicationContext定义好了
<bean id="user" class="com.junyipan.pojo.User"/>`
- @Value:相当于在IOC容器中的bean定义了property
<bean id="user" class="com.junyipan.pojo.User">
<property name="name" value="熊斌"/>
</bean>
- bean
- 属性如何注入
package com.junyipan.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component //组件,等价于<bean id="user" class="com.junyipan.pojo.User"/>
public class User {
@Value("熊斌")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
- 衍生的注解 @Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层 - dao 一般会使用【@Repository】注解,效果与@Component相同 - service 【@Service】 - controller 【@Controller】 这四个注解功能都是一致的,都是代表将某个类注册到ioc容器中,将类实例化,交给spring管理,完成bean的注册
- 自动装配
- @Autowired: 自动装配通过类型、名字
如果Autowired通过类型取出的不是唯一,则再通过名称匹配,也可以通过@Qualifier(value="xxxx")显式指定装配
- @Nullable:字段标记了这个注解,说明这个字段可以为null
- @Resource:自动装配通过名字、类型
- @Component: 组件,放在类上面,说明这个类被spring管理了,就是bean。
@Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层
- dao 一般会使用【@Repository】注解,效果与@Component相同
- service 【@Service】
- controller 【@Controller】
这四个注解功能都是一致的,都是代表将某个类注册到ioc容器中,将类实例化,交给spring管理,完成bean的注册
- 作用域@Scope
package com.junyipan.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component //组件,等价于<bean id="user" class="com.junyipan.pojo.User"/>
@Scope("singleton")
public class User {
@Value("熊斌")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
- 小结
xml与注解
- xml更加万能,适用于任何场合,维护简单方便
- 注解:不是自己类使用不了,维护相对复杂
最佳实践:
- xml用来管理bean
- 注解只负责完成属性注入
- 使用过程中,只需要注意:
xml <context:annotation-config/> <context:component-scan base-package="com.junyipan"/>
9. 使用Java方式配置Spring
完全使用java替代xml JavaConfig是Spring的一个子项目,在Spring4之后,它成为了一个核心功能 @Configuration @Bean