提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- spring框架
- 一、IOC容器在Spring中的实现
- Spring的bean组件
- IOC容器创建对象的方式
- 获取bean的三种方式和注意事项
- 依赖注入之setter注入
- 依赖注入之构造器注入
- 依赖注入之特殊值处理
- 依赖注入之为 类 类型的属性赋值(引用外部的bean)
- 依赖注入之为类类型的属性赋值(内部bean)
- 依赖注入之为数组类型的属性赋值
- 依赖注入之为list集合类型的属性赋值
- 依赖注入之为map集合类型的属性赋值
- 依赖注入之p命名空间
- Spring管理数据源和引入外部属性文件
- bean的作用域
- bean的生命周期
- FactoryBean 工厂bean
- 基于xml的自动装配之场景模拟
- 基于xml的自动装配之byType
- 基于xml的自动装配之byName
- 基于注解管理bean之功能分析
- 基于注解管理bean之注解和扫描
- 基于注解管理bean之扫描组件·有选择性的扫描
- 基于注解管理bean之bean的id管理
- 基于注解的自动装配 之@Autowired注解能够标识的位置
- 二、AOP-代理模式的概念
前言
提示:Spring 框架是一个分层的、面向切面的 Java 应用程序的一站式轻量级解决方案,它是 Spring 技术栈的核心和基础,是为了解决企业级应用开发的复杂性而创建的。
Spring 有两个核心部分: IOC 和 AOP。
核心 描述
IOC Inverse of Control 的简写,译为“控制反转”,指把创建对象过程交给 Spring 进行管理。
AOP Aspect Oriented Programming 的简写,译为“面向切面编程”。
AOP 用来封装多个类的公共行为,将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP 还解决一些系统层面上的问题,比如日志、事务、权限等。
spring框架
springframework
IOC思想和DI
ioc容器
反转控制:反转了资源的获取方向,从主动创建到被动获取框架已经创建好的
DI:依赖注入(就是说依赖哪个对象,spring就为哪个对象赋值,)
DI:就是IOC的一种表现形式,就是预先定义好的方式(例如:赋值 setter方法,有参构造)
一、IOC容器在Spring中的实现
BeanFactory接口,是ioc容器的基本实现,但是Spring内部的接口,不面向开发者属于父接口
IOC 主要功能就是帮助创建对象和赋值
ApplicationContext是BeanFactory的子接口,面向开发人员
ApplicationContext的主要实现类
FileSystemXmlApplicationContext实现类是通过读取文件系统路径下的xml容器
ClassPathXmlApplicationContext实现类是通过读取类路径下的xml容器
Spring的bean组件
IOC容器的根标签是beans ,beans里有若干的bean组成,bean就是IOC容器的组件
bean是表示spring管理xml文件的一个组件,就是spring管理的一个对象。
bean (自己配置一个bean对象,将对象交给IOC容器管理)
id:bean的唯一标识,不能重复
class:设置bean对象的类型,表现为该类的路径
IOC容器创建对象的方式
spring提供的对象,默认是单例的,一个bean就代表一个对象
可以通过将bean改为多例的(通过scope修改bean的作用域)
测试获取IOC容器,使用子接口ClassPathXmlApplicationContext实现类获取到xml配置文件,获取bean对象,getbean获取到bean。
有3种方式
IOC容器就是通过反射调用无参构造+工厂模式来创建对象
获取bean的三种方式和注意事项
获取bean有xml的方法和注解的方法
1、根据bean的id获取,但获取的是object类型需要强转
2、根据bean的类型获取,根据class对象的类型会自动匹配,一个类型的bean配置一次就够了
注意:根据类型获取bean时 要求IOC中有且只有一个类型匹配的bean,bean可以通过scope设置单例(singleton)或多例(prototype)
3、根据bean的 类型和id 来获取
如果组件类(交给IOC管理的类)实现了接口 ,那么根据接口类型也可以获取到bean是向上向下是兼容的,前提是bean是唯一的相反bean不唯一会报错
bean的类型,bean所继承的类型,bean所实现的接口的类型都可以获取到bean
依赖注入之setter注入
就是为当前的类 中的属性,赋值的过程叫做依赖注入有2种方式
一是:set注入
property属性:通过成员变量的set方法进行赋值
name:设置需要赋值的属性名(与set方法有关,与成员变量无关)
value:属性赋予的值
可以通过id+类型的方法获取到bean
依赖注入之构造器注入
构造器赋值
constructor - arg 标签
如果有多个符合条件构造方法可以通过 参数名或索引 指定赋值
依赖注入之特殊值处理
1、字面量
使用value属性给bean赋值是,spring 会吧value属性看做字面量
2、NULL值赋空值
3、CDATA节纯文本数据
依赖注入之为 类 类型的属性赋值(引用外部的bean)
ref引用:引用IOC中的某个bean的id 来为当前bean的某个属性赋值
就是在bean中给一个类 的类型为其赋值
依赖注入之为类类型的属性赋值(内部bean)
内部bean
在bean的property标签内部创建一个对象bean, 在内部bean为对象赋值(内部bean只能在内部使用,无法在IOC容器中获取的)
依赖注入之为数组类型的属性赋值
为数组赋值
在property标签内部赋值选择 array标签 为数组赋值
在array标签内根据数组的类型选择(ref引用 类类型,value 字符串,字面量)如果是字符串直接使用value赋值,如果是类类型,就是有ref引用bean对象赋值
依赖注入之为list集合类型的属性赋值
为集合属性类型赋值,
内部list集合赋值
第一种:在property标签内部使用 List标签 为list集合属性赋值
使用ref标签引用bean对象赋值
第二种:配置一个集合类型的bean,但是需要使用util的约束
加前缀util:list 取一个id名在集合中引用其他bean的对象达到赋值的目的
依赖注入之为map集合类型的属性赋值
为map集合类型赋值
map集合键值对的形式,因为map的集合能是任何类型
在property标签中使用map标签
1、在map标签中有 entry标签表示map的键和值,表示一个键值对
entry标签的 键:key字面量、key-ref 引用类类型 ,值:value 字面量、value-ref 引用类类型。
2、使用约束 util:map标签 里面有 entry标签表示map的键和值,表示一个键值对
entry标签的 键:key字面量、key-ref 引用类类型 ,值:value 字面量、value-ref 引用类类型。
在bean对象中直接引用map集合
依赖注入之p命名空间
p命名空间必须要有约束
用的不是标签赋值,用的是bean标签中的属性为各个属性赋值
属性带ref是给类类型赋值,不动ref的是给字面量赋值
Spring管理数据源和引入外部属性文件
需要在pom文件中导入mysql数据库的驱动和数据源 插件管理数据源
在IOC容器中获取到连接,连接数据库
创建properties文件 设置连接数据源的信息
把properties文件引入到spring配置文件中才能获取到properties文件中的数据
引入:需要用的context约束,选择property-placeholder标签,location来设置properties文件的路径
bean的作用域
spring的IOC容器管理的bean默认是单例模式
所获取的地址是同一个地址
可以通过scope修改bean的作用域
singleton单例IOC容器获取的是同一个地址
prototype多例IOC容器获取的就不是同一个地址
bean的生命周期
1、实例化
2、为属性赋值,依赖注入
3、初始化,需要通过bean的init-method属性指定初始化的方法
4.、IOC容器关闭时销毁,需要通过bean的destroy -method属性指定的方法销毁
因为ApplicationContext 没有提供关闭close 容器的方法,但她的子接口ConfigurableApplicationContext扩展了刷新和关闭容器的方法
FactoryBean 工厂bean
基于xml的自动装配之场景模拟
基于xml的自动装配之byType
基于xml的自动装配之byName
基于注解管理bean之功能分析
@Component:将类标识为普通组件,Component组件的意思
@Controller:将类标识为控制层组件
@service: 将类标识为业务层组件
@Reposltory:将类标识为持久层组件
这4个注解功能都是将类标识为组件,区别是各自的含义不一样,是给开发人员看的是在Component基础上扩展的新名字便于区分功能
基于注解管理bean之注解和扫描
类加上注解后,需要在xml配置文件中进行扫描,需要让spring知道哪些类加了注解,假的什么注解,spring需要扫描组件来获取
用context约束,中的组件扫描标签(component-scan标签中的base-package通过包扫描)会扫描包下的所有组件
通过注解加扫描的方式交给IOC容器作为组件进行管理,自身类和继承的父类和实现的接口都能够获取到对象
基于注解管理bean之扫描组件·有选择性的扫描
context:exclude-filter:排除扫描(后面跟上需要排除扫描的类型,spring就不扫描了)
type:设置排除扫描的方法
type=“annotation | assignable”
annotation:根据注解的类型排除,expression需要设置排除的注解的全类名
assignable::根据类的类型排除,expression需要设置排除的类的全类名
图,根据注解类型,类的类型排除扫描
context:include-filter:包含扫描(不常用)
注意:需要在context:component-scan 标签中设置use-default-filters=“false”
use-default-filters=“false”(常用)所设置的包下所有的类都需要扫描,此时可以使用排除扫描
use-default-filters=“true”(默认的)所设置的包下所有的类都不需要扫描,此时可以使用包含扫描
基于注解管理bean之bean的id管理
通过注解+扫描配置的bean的 id 名默认是该类的类名,小驼峰命名方法得到的类名
2、为组件注解+扫描所配置的bean自定义一个id名,可以在当前类的注解后面加一个参数名,就是自定义的bean的id名。
基于注解的自动装配 之@Autowired注解能够标识的位置
之前 是基于xml的自动装配,在配置文件中手动配置bean标签,通过bean标签中的autowired属性来实现自动装配的效果。
现在是注解加扫描的方式管理bean,需要通过注解的方式实现自动装配
@Autowired(自动装配)实现自动装配的注解
可以标识的位置
1、成员变量上,此时不需要设置成员变量的set方法/
2、标识在set方法上
3、为当前成员变量赋值的有参构造上
基于注解的自动装配之@Autowired的原理
bytype: 根据类型在IOC 容器中找到与该类型匹配的bean,为当前属性自动赋值
byname:将我们要赋值的属性名,作为bean的id ,在IOC容器中匹配到某个bean,来为当前的属性赋值
@Autowired:默认通过bytype的方法,在IOC 容器中通过匹配 某个bean为属性成员变量赋值
若有多个类型匹配的bean,它会自动转换成byname的方法实现自动匹配。
有多个有类型相同的bean时
@Qualifier注解,通过该注解的value属性值,指定某个bean的id,将这个bean为属性赋值
二、AOP-代理模式的概念
面向切面编程
现有代码的缺陷
针对带有日志功能核心代码与非核心代码混淆,不利于维护
解决办法
解耦 。把附加代码从业务代码中抽取出来
封装只能是连续运行的代码
什么是代理模式
对目标对象创建一个所对应的代理对象,访问目标对象时是先通过代理对象去间接的访问目标对象,代理对象会直接调用目标对象实现的功能
在代理对象中可以拓展目标对象执行前后其他的功能
,就是功能增强,在不改变目标方法的基础上,通过代理对象添加额外的操作,在不修改源码的情况下,增加功能
代理模式之静态代理实现
首先代理类实现目标类,并重写目标类里的所有方法
静态代理是一对一的,要将目标类声明出来,代理模式能够执行的位置,(目标方法执行前,目标方法执行后,catch 中,finally中,四个位置)
静态代理实现了解耦,但由于代码都写死了,不具备灵活性,用加日志举例,多个地方需要添加日志功能,就需要声明多个静态代理类日志,产生大量代码,功能分散没有统一管理
进一步新需求,将日志集中到一个代理类中,将来任何类有日志需求,就通过一个代理类实现,这就需要动态代理技术
代理模式之动态代理
动态代理:(分为:jdk动态代理,cglib动态代理),AOP的底层就是通过动态代理来实现的
动态代理就是,在程序运行期,创建目标对象的代理对象,并对目标对象中的方法进行功能性增强
分为jdk动态代理要求必须有接口,而且最终生成的代理类和目标类实现相同的接口,最终生成的代理类在com.sun.proxy包下,类名为$proxy2
proxyFactory(代理类工厂) 动态生成目标类所对应的代理类的一个工具类。
如何创建动态代理,动态生成的类object类型,使用jdk动态代理,通过反射实现的动态代理Proxy,通过创建代理实例方法newProxyInstance
newProxyInstance方法:就是通过这个方法创建的动态代理类包含的3 个参数包含
ClassLoader loader:类加载器(动态生成的类的类加载器,必须要先指定加载)
Class[] interfaces: 获取目标对象实现的所有的接口的class对象的数组(要保证目标对象和代理对象实现的目标是一致的)
InvocationHandler h :设置代理类中的抽象方法如何重写(里面只有一个invoke方法)
invoke(执行):他都3个参数,proxy表示代理对象,method表示要执行的方法,args表示要执行的方法的参数列表
AOP的概念、相关术语、作用
AOP 面向切面编程,属于OOP 面向对象编程的补充和完善, 横向抽取机制,
抽:把非核心代码抽出来交给切面类来管理
套:抽出来后套在目标对象抽出力的位置
1、横切关注点:非核心代码(在核心业务代码中中抽取出来的非核心代码)
2、通知
把收集的横切关注点封装到一个类中,这个类叫做切面
在切面内,每一个横切关注点在切面中表示一个通知方法
横切关注点就是非核心代码,这些非核心代码放在一个类中,这个类叫切面,对于切面来说,这些横切关注点叫做通知
基于注解的AOP之准备工作
基于注解的AOP
基于xml的AOP
AspectJ是AOP思想的一种实现方式
AspectJ本质是静态代理,依赖于weaver就是植入,Spring只是借用了Aspect中的注解
准备工作
添加aspects依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.22</version>
</dependency>
AOP 流程:
创建切面
创建通知
通过切入点表达式将通知作用到连接点
AOP的注意事项
切面类和目标类都要交给IOC容器管理
在切面类:中添加注解标识,注解@component为普通组件,注解@Aspect切面类注解,将当前普通组件标识为一个切面
在spring配置文件设置<aop:aspectj-autoproxy /> 标签,开启基于注解的AOP
基于注解的AOP之前置通知
通知类型:
在切面中需要通过指定的注解将方法标识为通知方法
当我们使用AOP时,在IOC容器中已经获取不到目标对象的方法,就需要通过代理对象间接 来访问
1、@Before (“execution( )”) 前置通知,在目标对象方法执行前执行。
(“execution( )”)切入点表达式:通过切入点表达式定位到目标对象中的方法上
基于注解的AOP之切入点表达式的语法
切入点表达式,设置在标识通知的注解的value属性中
@Before
(“execution( * com.lhz.spring.aop.annotation.calculatorImpl.add * (…))”)切入点表达式
第一个通配符 * 在这里代表任意访问修饰符和返回值类型
全类目:包名
第二个通配符* 代表类中的所有方法
(…)代表方法的参数列表 。。代表任意方法的任意的参数列表
获取连接点的信息
在通知方法的参数位置,设置joinPoint 类型的参数,获取连接点所对应的方法的信息
3.重用切入点表达式
1、@Pointcut声明一个公共的切入点表达式
2、@Pointcut(“execution( * com.lhz.spring.aop.annotation.calculatorImpl.add * (…))”)切入点表达式 /
3、Before(“pointCut”)直接调用公共的切入点表达式,做到重复使用
基于注解的AOP之各种通知的使用
@Before:前置通知,在目标对象方法执行前执行
@After:后置通知,在目标对象方法的finally字句中执行
@ AfterReturning :返回通知,在目标方法返回值之后执行
@AfterThrowing:异常通知,出现异常后执行的
基于注解的AOP之环绕通知
@Around:环绕通知的返回值要与目标方法的返回值一致
切面的优先级
一个验证切面类的准备工作
@component注解组件
@Aspect将组件标识为切面
将一个方法封装为一个通知方法就要用到@Before(“execution(切入点表达式)”)注解封装好,套到连接点
@Order()优先级,设置一个数值数值越小优先级越高