Spring
框架概述
- Spring是轻量级的JavaEE框架
- Spring可以解决企业应用开发的复杂性
- Spring有两个核心部分:IOC和AOP
- IOC:控制反转,把创建对象过程交给Spring容器进行管理
- AOP:面向切面编程,在不修改源代码的基础上进行功能加强
- Spring特点
- 方便解耦,简化开发
- AOP编程支持
- 方便程序测试
- 方便和其它框架进行整合
- 方便进行事物操作
- 降低API开发难度
IOC容器
- 什么是IOC:
控制反转:把对象创建和对象之间的关系交给Spring容器进行管理
- 使用IOC的目的:
降低耦合度
IOC底层原理
-
xml解析、工厂模式、反射
-
IOC过程
-
配置xml文件,配置创建的对象
<bean id="user" class="com.jiuheng.UserMapper" ></bean>
-
创建工厂类获取对象
class UserFactory{ public static UserMapper getUserMapper(){ String classCalue = class属性值; // 1.解析xml文件 Class clazz = Class.forName(classValue); //2.通过反射创建对象 return (UserMapper)clazz.newInstace(); //返回对象 } }
-
IOC接口
-
IOC思想是基于IOC容器完成,IOC容器底层是对象工厂
-
Spring提供IOC容器两种实现方式(两个接口):
-
BeanFactory:IOC容器基本实现,是Spring内部的使用接口,一般不提供开发人员进行使用
特点:加载xml配置文件时不会创建对象,在获取对象时才会创建对象
-
ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用
特点:在加载XML配置文件时就会把配置文件中的对象创建出来
-
-
IOC操作–Bean管理
什么是Bean管理:
Bean管理指的是两个操作:
1. Spring创建对象
2. Spring注入属性
Bean管理操作的两种方式:
- 基于XML配置文件方式
- 基于注解方式
Bean管理(基于XML文件方式)
-
基于xml方式创建对象
-
在Spring配置文件中使用bean标签,创建对象
<?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 id="user" class="com.jiuheng.entity.User" /> </beans>
-
bean标签中常见的属性:
- id属性:对象的唯一标识
- class属性:类的全路径
-
创建对象时默认是执行无参构造完成对象的创建
-
-
基于XML方式注入属性:
-
DI(依赖注入):就是注入属性
-
使用set方法注入
-
创建对象,对象属性及对象属性所对应的get,set方法
package com.jiuheng.entity; /** * @ClassName User * @Description user * @Author 程茂强 * @Data 2022/10/5 15:18 * @Version 1.0 */ public class User { private String name; private Integer age; public User() { } public User(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
-
在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 http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- set注入属性--> <bean id="user" class="com.jiuheng.entity.User" > <!-- 使用property标签完成属性注入 name: 类中的属性名称 value:向属性中注入的值 --> <property name="name" value="程茂强"/> <property name="age" value="19"/> </bean> </beans>
-
-
使用构造方法注入
-
创建对象,对象属性及构造方法
-
在Spring配置文件中配置对象创建,配置构造注入
<!-- 有参构造注入属性 --> <bean id="student" class="com.jiuheng.entity.Student"> <!-- 使用constructor-arg标签完成属性注入 name: 类中的属性名称 value:向属性中注入的值 --> <constructor-arg name="name" value="程茂强" ></constructor-arg> <constructor-arg name="age" value="19"></constructor-arg> </bean>
-
-
-
Xml注入其它类型属性
-
注入
null
和属性值包含特殊字符-
注入null值
<property name="name"> <null/> <!--向name属性中注入空值--> </property>
-
属性值中包含特殊字符(把特殊字符写入到CDATA中)
<property name="name"> <value><![CDATA[<<程茂强>>]]></value> </property>
-
-
外部Bean的注入
举例:
-
创建service类和mapper类
-
在service中调用mapper中的方法
public class UserService { private UserMapper userMapper; public UserMapper getUserMapper() { return userMapper; } public void setUserMapper(UserMapper userMapper) { this.userMapper = userMapper; } public void add(){ System.out.println("useService add ............"); userMapper.update(); } }
-
在spring文件中进行配置
<bean id="userService" class="com.jiuheng.service.UserService"> <property name="userMapper" ref="userMapper"></property> </bean> <bean id="userMapper" class="com.jiuheng.mapper.impl.UserMapperImpl"></bean>
-
-
注入属性–内部bean和级联赋值
当对象中的属性类型为其它对象时可以使用
<bean id="student" class="com.jiuheng.entity.Student"> <constructor-arg name="name" value="程茂强" ></constructor-arg> <constructor-arg name="age" value="19"></constructor-arg> <property name="user"> <bean id="user" class="com.jiuheng.entity.User"> <property name="name" value="程茂强"/> <property name="age" value="19"/> </bean> </property> </bean>
-
注入数组类型属性、注入List类型属性、注入Map类型属性
<bean id="book" class="com.jiuheng.entity.Book"> <property name="author"> <array> <value>张三1</value> <value>张三2</value> <value>张三3</value> </array> </property> <property name="list"> <list> <value>张三1</value> <value>张三2</value> <value>张三3</value> </list> </property> <property name="map"> <map> <entry key="Java" value="spring"/> <entry key="sql" value="mysql"/> </map> </property> </bean>
FactoryBean
Spring中有两种Bean类型,一种时普通的bean,另一种是工厂Bean(FactiryBean)
-
普通Bean
在xml配置文件种定义的Bean类型就是返回的类型
-
工厂Bean
在xml配置文件种定义的Bean类型可以和返回类型不一样
实现FactoryBean接口,实现接口中的方法
Bean的作用域
Spring默认对象是单实例对象(获取到的对象都是同一对象)
可以通过Spring配置文件中的bean标签的scope
属性进行设置
scope属性值:
singleton:单实例
prototype:多实例
singleton和prototype的区别:
-
singleton:单实例,prototype:多实例
-
设置scope值为singleton时,加载spring配置文件时就会创建单实例对象
设置scope值为prototype时,加载spring配置文件时不会创建实例对象,只有在getBean方法执行时才会创建多实例对象。
Bean的生命周期
- 通过构造器或工厂方法创建Bean实例
- 为Bean的属性设置值和对其它Bean的引用
- 调用Bean的初始化方法(需要自己配置)
- 正常使用Bean
- 当容器关闭时调用Bean的销毁方法(需要自己配置)
在Spring配置文件中的bean标签中有init-method
属性配置初始化方法
destory-method
属性配置销毁方法
Bean的后置处理器
bean 后置处理器允许在调用初始化方法前后对 bean 进行额外的处理
bean 后置处理器使用时需要实现接口:
org.springframework.beans.factory.config.BeanPostProcessor
。
在初始化方法被调用前后,Spring 将把每个 bean 实例分别传递给上述接口的以下两个方法:
postProcessBeforeInitialization(Object, String)
调用前
postProcessAfterInitialization(Object, String)
调用后
如果bean实例为单例那在容器运行时就会执行后置处理器方法和初始化方法,在容器销毁时又会执行销毁方法
总结一下后置处理器的执行过程:
-
通过构造器或工厂方法创建 bean 实例
-
为 bean 的属性设置值和对其他 bean 的引用
-
将 bean 实例传递给 bean 后置处理器的
postProcessBeforeInitialization()
方法 -
调用 bean 的初始化方法
-
将 bean 实例传递给 bean 后置处理器的
postProcessAfterInitialization()
方法 -
bean 可以使用了
-
当容器关闭时调用 bean 的销毁方法
Bean管理(基于注解方式)
Spring针对Bean管理中创建对象提供四个注解
- @Component
- @Service
- @Controller
- @Respository
属性注入Spring提供了以下注解
-
AutoWired:根据属性类型进行自动注入
-
@Qualifier:根据属性名称进行自动注入
-
@Resource:可以根据类型也可以根据名称自动注入
-
@Value:注入普通类型属性(字符串等)
AOP
AOP:面向切面编程
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各个部分之间的耦合度降低,提高程序的可重用性,同时提高开发效率。
通俗来讲:在不修改源代码的基础上,在主干功能里添加新功能。
底层原理
AOP的底层原理:动态代理
有接口情况–使用JDK动态代理
创建接口实现类的代理对象,增强类的方法
无接口的情况–使用CGLIB动态代理
创建当前类的子类代理对象,增强类的方法
AOP术语
-
连接点
可以被增强的方法被称为连接点
-
切入点
实际被增强的方法
-
通知
实际增加的代码逻辑部分
-
切面
把通知应用到切入点的过程
通知的类型
- 前置通知(Before):在目标方法被调用之前调用通知功能
- 后置通知(After):在目标方法完成之后调用通知,此时不关心方法的输出结果是什么
- 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为
- 异常通知(After-throwing):在目标方法抛出异常后调用通知
- 返回通知(After-returning):在目标方法成功执行之后调用通知
切入点表达式
作用:知道哪个类的哪个方法进行了增强
语法结构:
execution([权限修饰符] [返回值类型] [类的全限定名].[方法名] ([参数列表]) [异常类型])
其中权限修饰符和异常类型可以省略。
切入点通配符
* :单个独立的任意符号
… :多个连续的任意符号
-
返回值类型: * 表示任意返回值类型
-
方法名:* 表示所有方法
-
参数名:(…) 表示任意参数
(*) 表示任意一个参数
(*,*) 表示任意两个参数
切入点表达式例子
//指定切入点为项目中任意类的任意方法
execution(* *…*(…))
//指定切入点为com.jiuheng包下的所有方法
execution(* com.jiuheng.*.*(…))
//指定切入点为service层的所有方法
execution(* com.jiuheng.service.*.*(…))
//指定切入点为service层的save开头的方法
execution(* com.bighorn.service.*.save*(…))
//指定切入点为所有xxxService业务层接口的所有方法
execution(* com.jiuheng.*.*Service.*(…)) *
*//指定切入点为所有xxxService业务层接口的select开头的方法
execution( com.jiuheng.*.*Service.select*(…))
AspectJ注解操作AOP
-
在Spring配置文件加
@EnableAspectJAutoProxy(proxyTargetClass = true)
开启自动代理功能 -
添加切面
package com.jiuheng.log; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; /** * @ClassName Log * @Description 日志 * @Author 程茂强 * @Data 2022/10/6 13:42 * @Version 1.0 */ @Aspect @Component public class Log { @Before("execution(* com.jiuheng.*.*.*.*(..))") public void before(){ System.out.println("before执行"); } @After("execution(* com.jiuheng.*.*.*.*(..))") public void after(){ System.out.println("after执行"); } @AfterReturning("execution(* com.jiuheng.*.*.*.*(..))") public void after_returning(){ System.out.println("AfterReturning执行"); } }
当切入点相同时可以使用@Pointcut注解抽取
package com.jiuheng.log; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; /** * @ClassName Log * @Description 日志 * @Author 程茂强 * @Data 2022/10/6 13:42 * @Version 1.0 */ @Aspect @Component public class Log { @Pointcut("execution(* com.jiuheng.*.*.*.*(..))") public void pointCut(){ } @Before("pointCut()") public void before(){ System.out.println("before执行"); } @After("pointCut()") public void after(){ System.out.println("after执行"); } @AfterReturning("execution(* com.jiuheng.*.*.*.*(..))") public void after_returning(){ System.out.println("AfterReturning执行"); } }
当有多个增强类对同一方法进行增强时可以在增强类上添加
@Order(int)
注解,int值越小优先级越高