什么是Spring?
Spring框架是一个开放源代码的J2EE应用程序框架,是针对bean的生命周期进行管理的轻量级容器
Spring 的作用?
简化应用程序的开发
Spring核心-IOC
IOC介绍
IOC:控制反转,对象创建的权利由Spring框架完成,由容器管理对象的生命周期
- 谁控制谁,控制什么:IOC就是专门来控制对象的容器,都是由ioc容器来控制对象的创建,IOC容器控制对象,主要控制了外部资源的获取,不单单只是对象
- 为何反转,那些方面反转了:反转就是由容器来帮忙创建及注入对象,由容器帮我们查找到及注入依赖对象,对象只是被动的接受依赖对象,依赖对象的获取被反转了. 实现原理: 反射机制
容器的数据结构: K-V Map<K,V> key=bean中的ID, value=实例化的对象 程序执行过程:
- 指定配置文件的名称.
- 当Spring容器加载配置文件时.当按照顺序执行bean标签时,开始创建对象.
- Spring通过bean标签中的class属性获取类型的路径,之后通过反射机制,实例化对象(必须有无参构造)
- bean中的Id当做Map中的key, 将实例化的对象保存到Map中,当做value. 至此Spring容器启动成功!!!
- 当用户需要获取对象时,可以通过key/或者类型 获取对象.
IOC能做什么?
IoC对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC容器来创建并注入它所需要的资源了。
IoC很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”;即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。
Spring的注解
@Configuration 标识当前类是配置类
@Bean 标识该方法的返回值交给Spring容器管理
@ComponentScan(包名)包扫描注解 扫描注解
@Scope(“singleton”)/@Scope(“prototype”)单例多例模式
@PostConstruct 标识初始化方法
@PreDestroy 标识销毁方法.
Spring单例多例
说明
单例:Spring中保存一份对象
多礼:Spring容器负责创建多次对象,内存中对象多份
注解: @Scope(“singleton”)/@Scope(“prototype”)
结论
Spring容器在默认情况下,对象都是单例对象,节约内存空间
Spring容器提供了多例对象的方法,一般适用 数据库连接.资源连接等
Spring中的懒加载
懒加载:默认情况下Spring容器启动都会实例化对象
1.Spring容器启动时,对象创建不是懒加载
2.当用户需要时创建对象,才叫做懒加载
3.如果当前对象是多例模式,则都是懒加载
4.懒加载只对单例模式有效...
Spring的生命周期
- 对象创建
- 初始化数据
- 调用方法,完成功能
- 对象销毁
核心: 生命周期的方法都是自动调用!!!
@PostConstruct 标识初始化方法
@PreDestroy 标识销毁方法.
@Component注解的作用
Spring自动为该注解标识的类通过反射实例化对象,交给Spring容器管理.
- Key: 类名首字母小写 user
- value: 反射的对象
- 类似于@Bean注解
- @Component/@Bean区别:
- 1.@Component spring容器通过反射自动创建对象
- @Bean 是用户自己手动创建对象
- 2.@Component 标识类的
- @Bean 标识配置类中的方法
- 3.@Component 对象的Id是类名首字母小写
- @Bean 对象的Id是方法名
@ComponentScan说明
为了让Spring的注解生效. 需要单独使用包扫描注解.
Spring-DI
Spring中依赖注入
说明: 依赖注入就是将Spring容器中管理对象(数据),赋值给对象的属性.
核心机制: 如果需要使用依赖注入,则对象的属性必须有setxxx()方法
DI:依赖注入.由容器动态将某个依赖关系注入到组件之中,依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件的重用的频率,并为系统搭建一个灵活,可扩展的平台,
谁依赖于谁: 当然是应用程序依赖于IoC容器
●为什么需要依赖: 应用程序需要IoC容器来提供对象需要的外部资源
●谁注入谁: 很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象
●注入了什么: 就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)
IOC和DI的关系?
依赖注入明确描述了被注入对象依赖IOC容器配置依赖对象 实现代码的松耦合
依赖注入的方式
1.Set注入 <property name ="id" value = "200">
注入对象:<property name ="属性名" rel = "引用id">
2.构造方法注入<constructor-arg name="name" value="奔驰大G">\
Spring注解用法@Autowired
@Autowired:自动注入 规则:
- 1.默认条件下使用set方式注入.按照类型匹配.
- 2.set方式注入也可以按照name名称进行匹配
- 3.只要使用注解,默认自动生成SetXX方法
- 实现原理:
- 1.类型匹配: 如果是接口,则自动匹配其实现类对象
- 2.name名称匹配: 根据spring中的key进行注入.
多实现类的情况下@Qualifier
解决:
@Qualifier必须和@Autowired联用.
@Qualifier并且需要指定value的名称,就是spring中的key
Spring属性赋值-@Value注解
方法一:可以直接作用在属性上赋值@Value(值)
方法二:使用properties配置文件赋值@Value("${dept.name}")
MVC思想介绍
前提: 在项目中代码需要松耦合. 根据MVC指导思想.后端代码进行了优化,演变为现在的层级代码结构.
层级结构:
- Controller层 控制层 主要实现与前端页面的交互!!!
- Service层 业务层 主要实现数据的处理
- Dao层/Mapper层 持久层 与数据库进行交互.实现数据CURD操作.
Spring层级划分
1.Controller层 @Controller
2.Service层 @Service
3.Dao/Mapper层 @Repository
4.[POJO] 根据数据表定义的实体对象
在多线程条件下,共享数据必须序列化
层级加载流程
Map<UserMapperImpl,对象>
<UserServiceImpl,对象>
<UserController,对象>\
用户执行main()方法,程序开始调用
Spring容器开始执行 ApplicationContext
Spring容器按照指定的规则 加载配置类. 注意包路径
根据配置类的注解,开始完成包扫描 @ComponentScan(“com.jt.demo10”) 针对@Component注解有效
先扫描UserController,但是现在内存中没有依赖项UserService.所以当先线程先挂起(跳过!!!).继续执行后续动作.
当程序解析到Mapper层时 ,可以直接实例化对象交给Spring容器保存.
当程序解析到Service层时, 根据依赖注入的规则,注入Mapper的实现类.之后Service对象实例化成功
当程序加载完成之后,再次回到之前的Controller进行对象的注入.
注入UserService.之后UserController实例化成功.
\至此Spring容器启动成功!!!
Spring-AOP
AOP介绍
面向切面编程:通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑之间的耦合度降低,提高程序的可重用性,提高开发效率
主要作用:**在不修改源代码的情况下对方法进行扩展
原则:开闭原则 OCP原则 :在不改变原有代码的基础上,做功能的增强
切入点表达式:四种 Bean、within表达式、excution、annotation
通知:五种:前置、后置、返回、异常、环绕
代理模式:jdk代理(接口,兄弟关系),CGLIB代理(继承,父子关系)
IOC_DI和AOP之间的关系
1.IOC-DI:解决了框架和框架之间的耦合性问题
2.AOP:业务逻辑各个部分之间的耦合度降低
AOP注解
- @Aspect 标识当前类是一个切面\
- @Pointcut("表达式") 标识切入点表达式\
- @Before 通知注解\
- @EnableAspectJAutoProxy 让AOP生效在配置类配置
AOP的使用
切面 = 切入点表达式 + 通知方法
切入点表达式:
配置AOP为谁创建代理对象
1.bean(对象的ID);
2.within(包名,类名);
3.execution((返回值类型 包名.类名.方法名(参数列表)));
4.@annotation( 自定义注解的路径)
通知方法
作用: 当用户满足了切入点表达式,则才会执行扩展方法.
注意事项: 通知必须与切入点表达式绑定!!!
前置通知:@Before()在目标方法运行之前运行
后置通知:@AfterReturning(returning = "返回值")在目标方法之后运行
----动态获取返回值 属性:returning = "返回值"
异常通知:@AfterThrowing(throwing = "exception")目标方法抛出异常时执行
----对异常信息进行记录
最终通知:@After()不管目标方法执不执行,最终通知都要执行
环绕通知:\
- 前四大通知类型不能控制目标方法的运行,所以在使用时一般记录程序的运行状态.\
- 在目标方法执行前后都要运行, 只有环绕通知才可以控制目标方法是否运行. 使用最多的通知方法.\
关于连接点
说明:如果方法被切入点匹配,Spring会为其创建代理对象,则将这个方法称之为连接点 作用:可以通过连接点(JoinPoint)来获取方法的所有参数,提供给用户进行记录
关于JoinPoint和ProceedingJoinPoint区别
1.ProceedingJoinPoint只适用于环绕通知,因为只有环绕通知,才能控制目标方法的运行. 2.JoinPoint 适用于其它的四大通知类型,可以用来记录运行的数据. 3. ProceedingJoinPoint 中有特殊的方法proceed(); 4. 如果使用"JoinPoint" 则必须位于参数的第一位
通知切面的策略以及执行顺序
执行顺序:可以通过Order(1)注解数字越小越先执行 代理策略:@EnableAspectJAutoProxy(proxyTargetClass = true)强制使用CGlib代理