目录
1. 简介
Spring: 春天------>给软件行业带来了春天
概述
-
2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发布了1.0正式版本。
-
Spring理念:使现有技术更加实用。本身就是一个大杂烩,整合现有的框架技术。
-
经典: Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
优点 :
-
Spring是一个开源的免费框架
-
Spring是一个轻量级 , 非入侵式框架
-
控制反转(IOC) , 面向切面编程(AOP)
-
支持事务的处理 , 对框架整合的支持
详情简介参考各大网站
组成
扩展
SpringCloud
Spring官网介绍: 现代化Java开发! 基于Spring的开发
-
Spring Boot
一个快速开发的脚手架
基于SpringBoot可以快速的开发单个微服务
约定大于配置!
-
Spring Cloud
SpringCloud 是基于SpringBoot实现的.
学习SpringBoot的前提, 需要完全掌握Spring及SpringMVC!承上启下的作用!
2. IOC
IOC原型
1.创建dao层
package cn.you.dao;
public interface UserDao {
void getUser();
}
package cn.you.dao;
public class UserDaoImpl implements UserDao {
public void getUser() {
System.out.println("默认获取用户的数据");
}
}
package cn.you.dao;
public class UserDaoMysqlImpl implements UserDao{
public void getUser() {
System.out.println("Mysql获取用户数据!");
}
}
package cn.you.dao;
public class UserDaoOracleImpl implements UserDao{
public void getUser() {
System.out.println("Oracle获取用户数据! ");
}
}
2.创建service层
package cn.you.service;
public interface UserService {
void getUser();
}
package cn.you.service;
import cn.you.dao.UserDao;
import cn.you.dao.UserDaoOracleImpl;
public class UserServiceImpl implements UserService{
private UserDao userDao = new UserDaoOracleImpl();
public void getUser() {
userDao.getUser();
}
}
3.Test测试
import cn.you.service.UserService;
import cn.you.service.UserServiceImpl;
public class Test {
public static void main(String[] args) {
//用户实际调用的是业务层,dao层他们不需要接触!
UserService userService = new UserServiceImpl();
userService.getUser();
}
}
-
由于我们在UserServiceImpl类中我们手动选择了UserDaoOracleImpl,所以此时输出的为Oracle获取用户数据;(此时程序的选择在我们程序员选择);
-
然而用户的需求可能会影响我们原先的代码,所以我们需要对程序做出优化;
-
使用户想要什么样的选择,程序就会给出对于用户所选择的程序;
4.优化代码
修改UserServiceImpl类
package cn.you.service;
import cn.you.dao.UserDao;
public class UserServiceImpl implements UserService{
private UserDao userDao;
//利用set进行动态实现值得注入!
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}
public void getUser() {
userDao.getUser();
}
}
-
我们使用一个set接口实现,使程序本身发生了革命性的变化;
修改Test测试类
import cn.you.dao.UserDaoOracleImpl;
import cn.you.service.UserService;
import cn.you.service.UserServiceImpl;
public class Test {
public static void main(String[] args) {
//用户实际调用的是业务层,dao层他们不需要接触!
UserService userService = new UserServiceImpl();
((UserServiceImpl)userService).setUserDao(new UserDaoOracleImpl());
userService.getUser();
}
}
3.IOC本质
-
IOC是Spring框架的核心内容, 使用多种方式完美实现了IOC,可以使用注解,也可以使用XML配置, 新版Spring可以零配置实现IOC
-
Spring容器初始化时会先读取读取配置文件,根据配置文件或者元数据创建与组织对象储存容器中,程序使用时再从IOC容器中取出需要的对象.
注: 所谓的IOC就是对象由Spring来创建,管理,装配 !
5.使用xml文件实现IOC
创建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">
<!-- services -->
<bean id="mysqlImpl" class="cn.you.dao.UserDaoMysqlImpl"/>
<bean id="oracleImpl" class="cn.you.dao.UserDaoOracleImpl"/>
<bean id="userServiceImpl" class="cn.you.service.UserServiceImpl">
<property name="userDao" ref="mysqlImpl"/>
</bean>
<!--
ref : 引用Spring容器中创建好的对象
value : 具体的值 , 基本数据类型!
-->
</beans>
修改测试类
import cn.you.service.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestIOC {
public static void main(String[] args) {
// 获取ApplicationContext;
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//容器在手 天下我有 需要什么 就直接get什么
UserServiceImpl userServiceImpl = (UserServiceImpl) context.getBean("userServiceImpl");
userServiceImpl.getUser();
}
}
-
可以通过 ClassPathXmlApplicationContext 浏览底层代码
4. IOC创建对象的方式
新建一个maven项目
pojo
package cn.you.pojo;
public class User {
private String name;
public User(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
public void show() {
System.out.println("name="+name);
}
}
测试类
import cn.you.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test_ioc_02 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = (User) context.getBean("user");
user.show();
}
}
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="cn.you.pojo.User">
<constructor-arg index="0" value="王狗蛋"/>
</bean>
</beans>
<?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="cn.you.pojo.User">
<constructor-arg type="java.lang.String" value="王狗蛋"/>
</bean>
</beans>
<?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="cn.you.pojo.User">
<constructor-arg name="name" value="王狗蛋"/>
</bean>
</beans>
注: 可以看到在配置文件加载的时候 , 容器中管理的对象就已经初始化了 !
5.Spring配置
1. singleton 单例模式 (单线程)
-
(Default) Scopes a single bean definition to a single object instance for each Spring IoC container.
-
(默认)为每个SpringIOC容器将单个bean定义的范围限定为单个对象实例。
2. proptotype 原型模式(多线程)
-
Scopes a single bean definition to any number of object instances.
-
将单个bean定义的范围限定为任意数量的对象实例。
3. request
-
Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring
ApplicationContext
. -
将单个bean定义限定为单个HTTP请求的生命周期。也就是说,每个HTTP请求都有自己的bean实例,该实例是在单个bean定义的后面创建的。仅在支持web的Spring“ApplicationContext”上下文中有效。
4. session
-
Scopes a single bean definition to the lifecycle of an HTTP
Session
. Only valid in the context of a web-aware SpringApplicationContext
. -
将单个bean定义的范围限定到HTTP“会话”的生命周期。仅在支持web的Spring“ApplicationContext”上下文中有效。
5. application
-
Scopes a single bean definition to the lifecycle of a
ServletContext
. Only valid in the context of a web-aware SpringApplicationContext
. -
将单个bean定义限定为“ServletContext”的生命周期。仅在支持web的Spring“ApplicationContext”上下文中有效。
6. websocket
-
Scopes a single bean definition to the lifecycle of a
WebSocket
. Only valid in the context of a web-aware SpringApplicationContext
. -
将单个bean定义的范围限定到WebSocket的生命周期。仅在支持web的Spring应用程序上下文的上下文中有效。
6. Di依赖注入
1.构造器注入
@Autowired
2.Set注入[重点]
<?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="cn.you.pojo.Address">
<property name="address" value="上海"/>
</bean>
<bean id="student" class="cn.you.pojo.Student">
<!-- 第一种, 普通方式注入 -->
<property name="name" value="王狗蛋"/>
<!-- 第二种, Bean注入,ref -->
<property name="address" ref="address"/>
<!-- 数组注入,ref -->
<property name="books">
<array>
<value>红楼梦</value>
<value>西游记</value>
<value>水浒传</value>
<value>三国演义</value>
</array>
</property>
<!-- List注入 -->
<property name="hobby">
<list>
<value>敲代码</value>
<value>看电影</value>
<value>打游戏</value>
<value>听歌</value>
</list>
</property>
<!-- Map注入 -->
<property name="card">
<map>
<entry key="身份证" value="00000000000001"/>
<entry key="手机号" value="119"/>
</map>
</property>
<!-- Set注入 -->
<property name="games">
<set>
<value>DNF</value>
<value>LOL</value>
<value>CF</value>
</set>
</property>
<!-- null注入 -->
<property name="wife">
<null/>
</property>
<!-- Property注入 -->
<property name="info">
<props>
<prop key="userid">202107001</prop>
<prop key="sex">男</prop>
<prop key="username">王狗蛋</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
</beans>
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: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命名空间注入, 可以直接注入属性的值: property -->
<bean id="user" class="cn.you.pojo.User" p:name="王狗蛋" p:age="99"/>
<!-- c命名空间注入, 通过构造器注入: construct-args -->
<bean id="user2" class="cn.you.pojo.User" c:name="如花" c:age="18"/>
</beans>
7. Bean的作用域
-
自动装配是Spring满足bean依赖的一种方式
-
Spring会在上下文中自动寻找,并自动给bean装配属性
在Spring中的三种装配方式
-
在xml中显示的配置
-
在java中显示配置
-
隐藏的自动装配bean(重要)
测试
环境搭建: 一个人有两个宠物
1.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="cn.you.pojo.Cat"/>
<bean id="dao" class="cn.you.pojo.Dog"/>
<!--
byName: 会自动在容器上下文中查找
和自己对象set方法后面的值对应的 beanId !
-->
<bean id="people" class="cn.you.pojo.People" autowire="byName">
<property name="name" value="王狗蛋"/>
</bean>
</beans>
2.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="cn.you.pojo.Cat"/>
<bean id="dao" class="cn.you.pojo.Dog"/>
<!--
byType: 会自动在容器上下文中查找 和自己对象属性类型相同bean! -->
<bean id="people" class="cn.you.pojo.People" autowire="byType">
<property name="name" value="王狗蛋"/>
</bean>
</beans>
3.使用注解实现自动装配
-
导入约束: context约束
-
配置注解的支持: context:annotation-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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/context/spring-aop.xsd">
<!-- 配置注解的支持 -->
<context:annotation-config/>
<bean id="cat" class="cn.you.pojo.Cat"/>
<bean id="dao" class="cn.you.pojo.Dog"/>
<bean id="people" class="cn.you.pojo.People" >
</bean>
</beans>
可以看到我们使用了@Autowired注解 直接可以反射出Cat和Dao的show方法直接调用输出
-
@Atuowired 直接在属性上使用
拓展 :
@Nullable 字段标记了这个注解,说明这个字段可以为null;
注解内部
public @interface Autowired {
boolean required() default true;
}
测试
//如果显示定义了Autowired的required属性为false,说明这个对象可以为null,否则不能为空
@Autowired(required = false)
private Cat cat;
@Autowired
private Dog dog;
-
如果@Autwired自动装配的环境比较复杂, 自动装配无法通过一个注解[@Autowired]完成时的时候, 我们可以使用 @Qualifier(value="xxx")去配合 @Autowired 的使用, 使其指定一个唯一的Bean对象注入;
* @Resource : 自动装配通过名字/类型(该注解不是Spring是Java的)
-
@Resource和@Autowired的区别
-
都是用来自动装配的,都可以放在属性字段上
-
@Autowired 通过byType的方式实现,而且必须要求这个对象存在
-
@Resource 默认通过byname的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错 ! (常用)
-
执行顺序不通: @Autowired通过byType的方式实现 ;
@Resource通过byName的方式实现;
-
8.使用注解开发
-
在Spring 4 之后, 要使用注解开发,必须要保证 aop 包的导入
使用注解需要导入context的约束, 增加注解的支持!
1.bean
2.属性如何注入
// @Component组件
// 等于 <bean id="user" class="cn.you.pojo.User"/>
@Component
public class User {
public String name;
// 相当于 <property name="name" value="王狗蛋">
@Value("王狗蛋")
public void setName(String name){
this.name = name;
}
}
3.衍生的注解
-
@component : 有几个衍生注解,我们在web开发中,会按照mvc三层架构分层!
-
dao [@Repository]
-
service [@Service]
-
controller [@Controller]
这四个注解功能都是一样的, 都是代表将某个类注册到Spring中, 配置Bean
-
4.自动装配
@Autowired // 自动装配通过名字/类型
// 如果Autowired不能唯一自动装配上属性,则需要通过@Qualifier(value="xxx)来指定唯一bean
@Nullable // 字段标记了这个注解,说明这个字段可以为null;
@Resource // 自动装配通过名字/类型
5.作用域
// @Component组件 等于 <bean id="user" class="cn.you.pojo.User"/>
@Component
@Scope("singleton")//选择了单例模式
public class User {
public String name;
// 相当于 <property name="name" value="王狗蛋">
@Value("王狗蛋")
public void setName(String name){
this.name = name;
}
}
6.小结
xml与注解 :
-
xml 更加万能,适用于任何场景! 维护简单方便
-
注解 不是自己类使用不了,维护相对复杂!
xml与注解最佳实践 :
-
xml 用来管理bean
-
注解 只负责完成属性的注入
-
我们使用的过程中, 只需要注意一个问题: 必须让注解生效, 就要开启注解的支持
<!-- 指定要扫描的包,这个包下得注解就会生效 -->
<context:component-scan base-package="cn.you"/>
<!-- 配置注解的支持 -->
<context:annotation-config/>
9. 使用Java的方式配置Spring
我们现在完全不使用Spring的xml配置了,全权交给Java来做!
JavaConfig是Spring的一个子项目,在Spring4之后,他成为了核心功能!
-
@Configuration
-
这个也会Spring容器托管, 注册到容器中,因为他本来就是一个@Component
-
@configuration代表这是一个配置类,就和我们之前看的Beans.xml
-
实体类
//这个注解的意思,解释说明这个类被Spring接管了,注册到容器中
@Component
public class User {
private String name;
public String getName() {
return name;
}
@Value("李狗蛋")//属性注入值
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
配置类
//这个也会被Spring容器托管, 注册到容器中,因为他本来就是一个@Component
//@configuration代表这是一个配置类,就和我们之前看的Beans.xml
@Configuration
@ComponentScan("cn.you.pojo")
@Import(UserConfig2.class)
public class UserConfig {
//注册一个Bean , 就相当于我们之前写的一个bean标签
//这个方法的名字 , 就相当于bean标签中的id属性
//这个方法的返回值, 就相当于bean标签中的class属性
@Bean
public User getUser(){
return new User(); //就是返回要注入到bean的对象!
}
}
@Configuration
public class UserConfig2 {
@Bean
public User getUser(){
return new User(); //就是返回要注入到bean的对象!
}
}
测试类
public class Test {
public static void main(String[] args) {
//如果完全使用了配置类方式去做, 我们就只能通过 AnntationConfig 上下文来获取容器, 通过配置类的class对象加载!
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(UserConfig.class);
User getUser = (User) context.getBean("user");
System.out.println(getUser.getName());
}
这种纯java的配置方式,在springBoot中随处可见 !
10. 代理模式
为什么要学代理模式? 因为这是SpringAOP的底层 ! 面试必问[SpringAOP 和 SpringMVC]
代理模式的分类 :
-
静态代理
-
动态代理
1.静态代理
角色分析 :
-
抽象角色 : 一般会使用接口或者抽象类来解决
-
真实角色 : 被代理的角色
-
代理角色 : 代理真实角色 , 代理真实角色后 , 我们一般会做一些附属操作
-
客户 : 访问代理对象的人 !
代码步骤 :
1. 接口
//租房
public interface Rent {
public void rent();
}
2. 真实角色
//房东
public class Host implements Rent{
@Override
public void rent() {
System.out.println("房东要出租房子!");
}
}
3.代理角色
//代理
public class Proxy implements Rent{
private Host host;
public Proxy() {
}
public Proxy(Host host) {
this.host = host;
}
@Override
public void rent() {
seeHouse();
host.rent();
hetong();
fare();
}
//看房
public void seeHouse(){
System.out.println("中介带你看房");
}
//看房
public void hetong(){
System.out.println("签租赁合同");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
4.客户端访问代理角色
public class Client {
public static void main(String[] args) {
//房东要出租房子
Host host = new Host();
//代理,中介帮房东出租房子,但是代理角色一般会有一些附属操作!
Proxy proxy = new Proxy(host);
//你不用面对房东, 直接找中介租房即可!
proxy.rent();;
}
代理模式的好处 :
-
可以使真实角色的操作更加纯粹 ! 不要去关注一些公共的业务
-
公共也就交给代理角色 ! 实现了业务的分工 !
-
公共业务发生拓展的时候, 方便集中管理!
却点 :
-
一个真实角色就会产生一个代理角色; 代码量会翻倍 (开发效率会变低)
3.动态代理
-
动态代理和静态代理角色一样
-
动态代理的代理类是动态生成的, 不是我们直接写好的
-
动态代理分为两大类 : 基于接口的动态代理 , 基于类的动态代理
-
-
基于接口 -- JDK动态代理 (我们在这里使用)
-
基于类 : cglib
-
Java字节码实现 : javasist
-
我们需要了解两个类 : Proxy : , InvocationHandler : 调用处理程序实现的接口