Spring入门笔记1
IDE: IntelliJ IDEA 2020.2
零 l 写在前面
1、以初学者的视角记录笔记
2、课程链接:[链接]
3、资料链接:[笔记对应课程的配套资料],提取码:saq4
4、实操很重要!!!
5、本文主讲控制反转(IoC)
一 l 简单介绍(了解)
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
控制反转(IoC):本来是在程序内new的对象,交由Spring进行创建
Spring 体系结构:
Spring在项目中的架构:
二 l 快速入门
(一)下载解压
1、下载Spring并解压:
教程链接
下载链接
2、下载commons-logging-1.x-bin.zip并解压
(二)提取需要的文件到一个文件夹中
1、在spring-framework-x.x.x.RELEASE文件夹中的libs文件夹中取出其中的4个核心jar包
jar包名 | 作用 |
---|---|
spring-core-x.x.x.RELEASE.jar | 包含Spring框架基本的核心工具类,Spring其它组件要都要使用到这个包里的类,是其它组件的基本核心。 |
spring-beans-x.x.x.RELEASE.jar | 所有应用都要用到的,它包含访问配置文件、创建和管理bean以及进行Inversion of Control(IoC) / Dependency Injection(DI)操作相关的所有类 |
spring-context-x.x.x.RELEASE.jar | Spring提供在基础IoC功能上的扩展服务,此外还提供许多企业级服务的支持,如邮件服务、任务调度、JNDI定位、EJB集成、远程访问、缓存以及各种视图层框架的封装等。 |
spring-expression-x.x.x.RELEASE.jar | Spring表达式语言 |
2.2.在commons-logging-1.x文件夹中提取commons-logging-1.x.jar(与课程中jar包名字不一样没关系)
(三)导入到项目中
1、
2、
(四)依赖注入(DI)是什么意思
依赖注入相当于在配置文件中执行了一次set方法(需要实现set方法)
<!-- 配置一个bean 【对象】-->
<bean id="userService" class="com.gyf.service.UserService">
<!-- 依赖注入数据,调用属性的set方法 -->
<property name="name" value="qwe"></property>
</bean>
spring内部创建对象的原理:反射
1.解析xml文件,获取类名,id,属性
2.通过反射,用类型创建对象
3.给创建的对象赋值
三 l 加载Spring容器配置的三种方式
Spring通过xml配置文件,加载Bean(Bean似于类的实例),从而实现对Bean的统一控制。
现在可以粗略的理解为 .xml配置文件加载的东西 就是 Spring容器 。
加载配置 比 配置Bean 简单点,所以放在第三部分。
(一)介绍
1、spring的配置文件放在src目录下(相对路径)【最常用】
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
2、文件系统路径获得配置文件(绝对路径)
ApplicationContext context = new FileSystemXmlApplicationContext("绝对路径");
3、使用BeanFactory【了解】【过时方法】
BeanFactory factory = new XmlBeanFactory(new FileSystemResource("绝对路径"));
(二)BeanFactory和ApplicationContext对比
1、BeanFactory 第一次getBean时才会初始化Bean【延迟加载】
2、ApplicationContext 是对BeanFactory扩展,提供了更多功能【即时加载】
(加载配置的文件之后即刻加载类)
(1)国际化处理
(2)事件传递
(3)Bean自动装配
(4)各种不同应用层的Context实现
四 l Bean(xml配置文件中)
知道了怎么加载Spring容器,接下来就要学着配置 Bean的设置 了。
(一)装配Bean的三种方式
1、new 对象,class 是实例类
<bean id="userService1" class="com.gyf.service.UserServiceImpl"></bean>
2、静态工厂,使用工厂类的静态方法 new 对象
<bean id="userService2" class="com.gyf.service.UserSereviceFactory1" factory-method="createUserService"></bean>
3、实例工厂,new 一个工厂类,再调用工厂方法 new 对象,factory-bean:工厂实例
<bean id="factory2" class="com.gyf.service.UserSereviceFactory2"></bean>
<bean id="userService3" factory-bean="factory2" factory-method="createUserService"></bean>
(二)bean的作用域
类别 | 说明 |
---|---|
singleton(默认) | 在Spring IoC容器中仅存在一个Bean实例,Bean以单例方式存在,默认值 |
prototype | 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时 ,相当于执行new XxxBean() |
request | 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境 |
session | 同一个HTTP Session 共享一个Bean,不同Session使用不同Bean,仅适用于WebApplicationContext 环境 |
globalSession | 一般用于Portlet应用环境,该作用域仅适用于WebApplicationContext 环境 |
prototypre使用例子:
<bean id="userService" class="com.gyf.service.UserService" scope="prototype"></bean>
(三)bean的生命周期(了解)
1、instantiate bean对象实例化【new对象】
2、populate properties 封装属性【调用set方法赋值】
3、如果Bean实现BeanNameAware 执行 setBeanName【设置bean名】
4、如果Bean实现BeanFactoryAware 执行setBeanFactory ,获取Spring容器【把对象放进工厂,放进容器】
5、如果存在类实现 BeanPostProcessor,执行preProcessBeforeInitialization【批量预处理】
6、如果Bean实现InitializingBean 执行 afterPropertiesSet 【属性赋值完成】
7、调用 指定初始化方法 init【调用自定义初始化方法】(init-method属性)
8、如果存在类实现 BeanPostProcessor(处理Bean) ,执行postProcessAfterInitialization
执行业务处理【批量后处理】
9、如果Bean实现 DisposableBean 执行 destroy【调用销毁bean容器方法】(需要手动关闭容器)context.getClass().getMethod("close").invoke(context);
10、调用 指定销毁方法 customerDestroy【调用自定义销毁方法】(destroy-method属性)
5和8单独处理的例子,对所有bean都有效:
// MyBeanPostProcessor.java
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//这边可以用于多个对象共同的事情的处理
System.out.println("5:预处理:" + bean + ":" + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("8:后处理:" + bean + ":" + beanName);
return bean;
}
}
// beans.xml
<bean id="beanProcess" class="com.gyf.model.MyBeanPostProcessor"></bean>
五 l 依赖注入Bean属性(xml)
通过第四部分的学习,现在可以构造一个Bean(实例)。
接下来,就可以想着能不能顺便给Bean赋初值。
(一)手动装配,使用xml配置
1、构造方法注入1
<bean id="stu" class="com.gyf.model.Student">
<!-- 相当调用 public Student(String username, String password) 构造方法 -->
<!-- name:构造属性名; value:数值 -->
<constructor-arg name="username" value="qwe"></constructor-arg>
<constructor-arg name="password" value="1"></constructor-arg>
</bean>
2、构造方法注入2
<!-- 通过索引加类型 给构造方法赋值 -->
<bean id="stu" class="com.gyf.model.Student">
<constructor-arg index="0" value="qwe" type="java.lang.String"></constructor-arg>
<constructor-arg index="1" value="2" type="int"></constructor-arg>
</bean>
3、属性setter方法注入
<!-- 2.通过set方法往bean注入属性值 -->
<bean id="stu" class="com.gyf.model.Student">
<property name="username" value="qwe"></property>
<property name="password" value="3"></property>
<property name="age" value="3"></property>
</bean>
4、p命名空间注入【了解】
<!-- xmlns xml namespace:xml命名空间,注意xmlns:p这一行 -->
<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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 3.通过p命名空间注入 -->
<bean id="stu" class="com.gyf.model.Student"
p:username="qwe" p:password="4" p:age="4"></bean>
(二)SpEL表达式【了解】
Spring 表达式:对<property>进行统一编程,所有的内容都使用value
表达式 | 意义 |
---|---|
#{123}、#{‘jack’} | 数字、字符串 |
#{beanId} | 另一个bean引用 |
#{beanId.propName} | 操作数据 |
#{beanId.toString()} | 执行方法 |
#{T(类).字段|方法} | 静态方法或字段 |
(三)集合注入(给集合注入数据)
集合的注入都是给<property>添加子标签
集合类型 | 子标签 |
---|---|
数组 | <array> |
List | <list> |
Set | <set> |
Map | <map> ,map存放k/v 键值对,使用<entry>描述 |
Properties | <props> <prop key="">value</prop> |
普通数据 | <value> |
引用数据 | <ref> |
例子:
<bean id="programmer" class="com.gyf.model.Programmer">
<!-- list类实例cars -->
<property name="cars">
<list>
<value>ofo</value>
<value>mobai</value>
<value>宝马</value>
</list>
</property>
<!-- set类实例pats -->
<property name="pats">
<set>
<value>小黑</value>
<value>小黄</value>
<value>小白</value>
</set>
</property>
<!-- map类实例infos -->
<property name="infos">
<map>
<entry key="name" value="qwe"></entry>
<entry key="age" value="1"></entry>
<entry key="ip" value="127.0.0.1"></entry>
</map>
</property>
<!--Properties类实例mysqlInfos(数据库连接信息) -->
<property name="mysqlInfos">
<props>
<prop key="url">mysql:jdbc://localhost:3306/dbname</prop>
<prop key="user">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
六 l 依赖注入Bean属性【特殊的注入——注解注入】【重点】
在xml中配置好像过于繁琐了,通过一步步的学习,已经了解了各种方法。
最后,通过 注解 返璞归真的同时,更进一步减少代码量。
现在,试试回到 java代码 中去配置。
1、注解注入的准备
(1)把spring-framework-x.x.x.RELEASE文件夹中的libs文件夹中取出spring-aop-x.x.x.RELEASE.jar到之前的包文件夹里。(不然可能会报NoClassDefFoundError的错误)
(2)在xml配置文件中的beans添加成如下样式(重点看第3、6、7行);再添加两行注解代码。
<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
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启注解-->
<context:annotation-config/>
<!-- 注解的位置-->
<context:component-scan base-package="com.gyf"/>
</beans>
2、基本spring注解
注解:就是一个类
使用方式:在实现类或接口前一行添加 “@注解名称”(在接口前添加会自动找实现类)
为什么使用:开发中使用注解取代 xml 配置文件。
注解 | 等价bean定义 |
---|---|
@Component | <bean class=“类”> |
@Component(“id”) | <bean id=“别名” class=“类”> |
tips:
(1)如果@Component没配置id,可以通过类获取:
IUserService service = (IUserService) context.getBean(IUserServiceImpl.class);
有id使用:
IUserService service = (IUserService) context.getBean("id");
例子:
// UserDaoImpl.java
@Component
public class User{
}
等价于
<!-- beans.xml -->
<bean id="userService" class="com.qwe.service.User">
3、在web开发中产生的衍生
阿里巴巴开发手册中有请求处理层(Web层)、业务逻辑层(Service层)、通用逻辑层(Manager层)、数据持久层(DAO层)
层级 | 对应注解 |
---|---|
Web层 | @Controller(“名称”) |
Service层 | @Service(“名称”) |
DAO层 | @Repository(“名称”) |
(1)以上三个注解的用法与@Component相同
(2)为什么会有衍生:保证生成的顺序从DAO层->Service层->Web层
4、其他注解
其他注解 | 功能 |
---|---|
@Autowired | 自动 根据类型 注入 同类型Bean(需要存在)。一般只用这个,不用下两个 |
@Qualifier(“名称”) | 指定自动注入的id名称【指定Bean】 |
@Resource(“名称”) | 等于@Autowired加@Qualifier(“名称”) |
@ PostConstruct | 自定义初始化。相当于bean属性 init-method=“方法名” |
@ PreDestroy | 自定义销毁。相当于bean属性 destroy-method=“方法名” |
@Scope(“作用域”) | 设置bean的作用域。相当于bean属性 scope=“作用域” |
5、例子
(1)不使用注解的例子
java文件:
// DAO层 UserDao.java
public class UserDao implements IUserDao{
@Override
public void add(User user) {}
}
// service层 UserService.java
public class UserService implements IUserService {
private IUserDao userDao;
@Override
public void add(User user) {
//调用dao
userDao.add(user);
}
public IUserDao getUserDao() { return userDao; }
public void setUserDao(IUserDao userDao) { this.userDao = userDao; }
}
// web层 UserAction.java
public class UserAction{
private IUserService userService;
public void save(User user){
userService.add(user);
}
public IUserService getUserService() { return userService; }
public void setUserService(IUserService userService) { this.userService = userService; }
}
xml配置文件:
<!-- 1.配置dao-->
<bean id="userDao" class="com.gyf.dao.UserDao"></bean>
<!-- 2.配置service -->
<bean id="userService" class="com.gyf.service.UserService">
<property name="userDao" ref="userDao"></property>
</bean>
<!--3.配置action-->
<bean id="userAction" class="com.gyf.web.action.UserAction">
<property name="userService" ref="userService"></property>
</bean>
程序调用userAction.save()->调用userService.add()->调用userDao.add()
(2)使用注解的例子
java文件:
// DAO层 UserDao.java 使用@Repository作为注解
@Repository
public class UserDao implements IUserDao{
@Override
public void add(User user) { System.out.println("dao 添加用户:" + user); }
}
// service层 UserService.java 使用@Service作为注解
@Service("myUserService")
public class UserService implements IUserService {
@Autowired // spring会自动注入userDao赋值,不用get和set方法了
private IUserDao userDao;
@Override
public void add(User user) {
//调用dao
userDao.add(user);
}
}
// web层 UserAction.java 使用@Controller作为注解
@Controller
public class UserAction{
@Autowired // spring自动注入userService赋值
@Qualifier("myUserService") // 根据指定的id注入属性
// @Resource(name = "myUserService") // 等价上面两个
private IUserService userService;
public void save(User user){
System.out.println("action save方法 ");
userService.add(user);
}
}
xml配置文件:只需要开启注解
七 l 总结
(一)对IoC理解
假设有一个金字塔的三层结构,数据从顶到底流通,每一层都会有很多的类,除底层外每一层都依赖于下一层。
第一步:
每实例化一个类的时候同时递归实例化底层的类。
优点:
实现简单
缺点:
每一层相同类的实例数据不互通且冗余,随着实例的增加,冗余线性提升
第二步:
在金字塔额外创建一个工具(含多个类),专门管理金字塔中类的实例。
优点:
方便管理与通信
缺点:
这个工具的实现会极其的复杂
这种管理类的工具的控制方法就是控制反转(IoC)
spring可以很方便的使用类的实例而不用担心类之间的依赖
(二)对本文的总结
第二部分是快速入门
第三部分是加载xml配置
第四五六部分才是IoC的内容,其中又分为xml配置和注解配置
全文的重点应该在第六部分的注解配置上,注解配置相当于在xml中定义+依赖注入(第四五部分内容)