1.IOC概念以及原理:
什么是ioc? 1.IOC(DI)概述: Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。DI概述: DI—Dependency Injection,即“依赖注入”:组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。2.ICO前生: 1.分离接口与实现: 例子:生成HTML或PDF格式的不同类型的报表 2.采用工厂设计模式: 3.采用反转控制 IOC底层原理: 1.xml解析 2.工厂模式 3.反射原始方式: 工厂模式:
实际意义:service和dao的耦合度减少,dao层变了,修改工厂类,且是Static的,提高了代码重用率
IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
Spring提供IOC容器实现的两种方式
BeanFactory:IOC基本设施:提供了贡多的高级特性大多数我们使用ApplicationContext ,在你记载配置文件的时候,不会创建对象,只有你加载,才会创建ApplicationContext是BeanFactory的子接口,加载xml配置文件的时候就创建类了,主要实现类: ClassPathXmlApplicationContext:从类路径下加载配置文件 refresh():刷新上下文 close():关闭上下文 FilesSystemXmlApplicationContext:从文件系统加载配置文件调用ApplicationContext的getBean()方法 1.参数尽量写id,不写class型,除非配置的bena唯一基于xml方式创建对象(IOC):
配置XML文件,在IOC容器加入bean,并配置属性 bean常用属性讲解: id:唯一标识 name:和id差不多,但不可以加入特殊符号 class:类全路径(通过路径再反射获得地址码)创建对象的时候,默认也是执行无参数构造方法基于xml方式注入属性:
DI:依赖注入,就是注入属性,在创建对象的基础之上,基于IOC的具体实现 第一种注入方式:使用set方法进行注入 1. 创建对象,并创建set 方法 2.在Spring配置文件文件中,通过property来配置 第一种注入方式:使用构造器进行注入 1. 在你的类配置构造器,必须要有无参构造器!!!! 2. 在Spring配置文件通过constructor来配置 通过p命名空间来给属性赋值: 需要先导入p命名空间 2.在Spring配置文件 ,通过p命名空间,来配置属性(只是用与你的bean有setter) 注入空值和特殊符号 空值:在当前标签的子节点使 特殊符号:如果value属性或者字标签的值包含特殊字符如<>,那么必须要写成<![CDATA[值 ]]>(或者转义) 注入属性bean: 外部bean: 1. 创建两个类service和dao,并建立set方法 2. 在service调用dao里面的方法 内部bean和级联赋值: 内部bean 在你的bean中添加好级联属性: 直接在你的Spring配置文,嵌套bean 级联赋值 通过ref,以及外部bean的联用: 注入集合属性 1.集合赋值对象和公共集合 集合赋值对象: 1. 先建立对应的集合 2.在spirng配置文件直接配置就可以了
独立集合
FactoryBean
普通bean:在配置文件中定义bean类型就是返回类型工厂bean:在配置文件中定义bean类型不一定就是返回类型 1. 第一步 创建类 ,让这个类作为工厂bean,实现接口FactoryBean 2. 第二步 实现接口FactoryBean里面的方法,在实现的方法中定义返回的bean类型Bean的作用域 使用bean的scope来配置bean的作用域 singleton:默认值,容器初始创建bean实例,在这个容器的生命周期只创建这个一个bean,单例的 prototype:原形的,容器初始化是不创建bean,在每次请求的时候,调用getbean()方法的时候创一个bean实例,并返回一个 1.默认情况下,Spring中的bean的实现都是单实例的 当你在spring上下文,设置属性scope 那么,运行结果
bean生命周期
生命周期 1.从对象创建到销毁的过程
bean生命周期
通过构造器创建bean实例(无参构造器)为bean的属性设置值和对其他bean的引用(调用set方法)调用bean的初始化方法(需要进行配置)bean创建完成,可以使用了当容器关闭,调用bean销毁的方法(需要进行配置)bean的后置处理器
通过构造器创建bean实例(无参构造器)为bean的属性设置值和对其他bean的引用(调用set方法)把bean实例传递给bean后置处理器的方法调用bean的初始化方法(需要进行配置)把bean实例传递给bean后置处理器的方法bean创建完成,可以使用了当容器关闭,调用bean销毁的方法(需要进行配置) 后置处理器的演示: 1.创建类,实现接口BeanPostProcessor,创建后置处理器 2. 在Spring上下文配置文件bean的自动装配
byName 根据当前Bean的id的setter风格的属性名自动装配,如果也有匹配的,则成功;若没有,则不装配 byType 根据bean的class和当前bean的类型进行装配,但是当出现两个或多个同类型的bean,会异常 15. 调用外部文件:
基于注解简绍
什么是注解:代码里面的特殊标记目的:简化代码Spring针对Bean管理中创建对象提供注解
@Component:基本注解,标志了一个手Spring管理的组件@Respository:标识持久层@Service:表示服务层(业务层)组件@Controller:标识表现层组件 注意:功能是一样的,但是为了让你更加清晰,所以分开使用基于注解实现对象的创建
配置扫描器(componet-scan)在你的Spring配置文件 在对应的包里的bean 加上注解组件扫描的细节配置: 1. base-package:指定一个扫描的包,可以选多个包,用逗号隔开 2. resource-pattem: 表示当前报下指定的一个类 3. context:include-filter(指定类): 字节点表示只包含的目标类,注意!!!:使用这个属性的时候要设定use-default-filters=“false”,意思就是不再是用官方的默认指定 4. context:exclude-filter(指定类): 字节点表示排除的目标类 5. 注意: context:include-filter和context:exclude-filter可以是context:component-canf的子节点 注意这两个方法有一个属性type:annotation:根据注解名称,只扫描注解。assinable :根据类名称,只扫描选定类 6. expression: 表示只扫描某一种注解
基于注解方式实现属性注入
@AutoWired: 根据属性类型进行自动装配 第一步:把service和dao添加创建对象注解 第二步:把service注入dao对象,在service添加
@Qualifier: 当你需要一个指定名称的对象/属性时,你可以在@AutoWired的下面添加这个注解设置value值,必须要和目标注解的value对应
@Resource:既可以根据类型,名称注入
@Value:注入普通类型的属性
完全注解开发:
创建配置类,替代xml配置文件
编写测试类
AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
使用"横切"技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
好处: 1.每个事物逻辑位于一个位置,代码不分散,便于维护和升级 2.业务模块更加简洁。只包括核心业务代码有两种情况动态代理
有接口 使用JDK动态代理 创建接口实现类代理对象,等价于new 但不是new
无接口 使用CKLIB动态代理 创建子类实现类代理对象,等价于new 但不是new
JDK动态代理实现(使用Proxy) 1.创建对应的接口,和实现类 2.使用Proxy,代理对象
AOP术语: 连接点:类里面那些方法可以被增强,这些方法成为连接点切入点:实际被真正增强的方法,成为切入点通知(增强):就是你想要的功能,也就是 安全,事物,日志等 它有多种类型:前置,后置,环绕,异常,最终通知切面 :是一个动作,把通知应用到切入点过程个人理解:让切入点(犯法)通过连接点判断通知的位置(连接点)这叫做切面,而通知则会告诉你,什么时候干,干什么.切面这个过程会告诉你在哪里干 Aop操作(准备)Spring框架一般都是基于AspectJ实现AOP操作
什么是AspectJ? AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用。进行Aop操作加入jar包
基于AspectJ实现Aop操作
基于xml配置文件实现(了解就好)
创建两个类,增强类和被增强类,创建方法在Spring配置文件中创建两个类对象在Spring配置文件中配置切入点基于注解方式实现(使用) 1.创建被增强类,在类里面定义方法 2. 创建增强类,让不同的方法代表不同的通知 3. 在你的Spring配置文件开启注解扫描 4. 在你的类加上注解
配置不同类型的通知 package AOP.AOP_annotation; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; //增强类 @Component //表示生成了代理对象 @Aspect public class UserProxy { @Pointcut("execution(public int AOP.AOP_annotation.User.add())") //为了让切点表达式重用,这里建立表示切点表达式的方法 public void pointcut(){ } // JoinPoint:可以联动被增强这个方法 //前置通知 @Before("execution(public int AOP.AOP_annotation.User.add())") public void before(JoinPoint j){ System.out.println("before:"+j.getSignature().getName()); } //后置通知 @After("execution(public int AOP.AOP_annotation.User.add()))") public void after(){ System.out.println("after"); } //返回通知: //在方法正常结束后执行的代码 //返回通知是可以访问到方法的返回值! @AfterReturning(value = "execution(public int AOP.AOP_annotation.User.add()))",returning = "res") public void AfterReturning(int res){ System.out.println("AfterReturning:"+res); } //异常通知:只有异常的时候才会执行,可以返回异常 @AfterThrowing(value = "execution(public int AOP.AOP_annotation.User.add()))",throwing = "s") public void AfterThrowing(Exception s){ System.out.println("AfterThrowing:"+s.toString()); } /*环绕通知,功能很强,但是并不常用 *环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法 *且环绕通知必须有返回值,返回值为目标方法的返回值 */ @Around("execution(public int AOP.AOP_annotation.User.add()))") public void Around(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("环绕之前"); //被增强的方法执行 Object proceed = joinPoint.proceed(); System.out.println("环绕之后·"); } } 切入点表达式 切入点表达式作用:知道对那个类里面的那个方法进行增强语法结构:execution([权限修饰符][返回类型][类全路径][方法名称][参数列表]) 例子:在com.atguigu.dao.BookDao类的add()方法进行增强 execution(* void com.atguigu.dao.BookDao.add(int,int )) 切入点表达式的重用 切面的增强顺序 默认是看类文件的名字在增强类上面添加注解@Order(数值),数字值越小优先级越高 完全注解开发创建银行转账表
建立对应的 dao service 层并写入转账方法 如果在addMoney方法后发生未知异常,但是addMoney已经执行完了,就会出现作错误
解决办法:事务事务操作:
事务添加到JavaEE三层架构的Service层(业务逻辑层)
两种方式:编程式事务管理和声明式事务管理(使用)声明式事务管理:
基于注解方式
配置事务管理器:
在Spring配合文件开启事注解 1. 加入名称空间tx,开启事务注解
在你的service类上面获取service类里面方法上面添加事务注解 注意:@Transactional既可以加在类上面,也可以加在方法上面 区别就是将事务套在类上或方法上
当你方法出现异常的时候,你的数据也没发生改变
基于xml配置文件方式(了解) 1. 在Spring配置文件,设置事务管理器,配置通知 2. 配入切入点和切面 3.
在Spring进行声明式事务管理,底层使用Aop原理
Spring事务管理的API
提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类声明式事务的参数配置
propagation():事务传播行为 1. 多事务方法,直接进行调用,这个过程中事务是如何进行管理的 2. 事务传播行为:事务方法的互相调用 3. 事务七种传播行为:
ioslation:事务隔离级别
事务有特性:隔离性,多事务操作之间不会产生影响,若不考虑隔离性产生很多问题有三个读的问题: 1.脏读:一个未提交事务读到另一个未提交事物的数据 2. 不可重复读:一个未提交事务读取到另一提交事务修改数据虚读:一个未提交事务读取到另一提交事务修改数据 解决办法:设置隔离级别属性ioslation,默认是REPEATABLE READ
timeout:超过时间 事务需要在一定时间内进行提交,如果不不提交进行回滚 默认值为-1,设置时间一秒单位进行计算
readonly:是否只读 读:查询,写:增删改 默认值:false
rollbackfor:回滚 设置哪些异常回滚
norollbackfor:不回滚 设置哪些异常不回滚
package Transaction.CompletelyAnnotation; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.transaction.annotation.EnableTransactionManagement; @Configuration//配合类 @ComponentScan(basePackages = "Transaction")//组件扫描 @EnableTransactionManagement//开启事务 public class TxConfig { //创建数据库连接池 @Bean public DruidDataSource getDruidDataSource(){ DruidDataSource dataSource=new DruidDataSource(); return null; } @Bean public JdbcTemplate getJdbct(){ return null; } }创建log4j2的配置文件
在这里我们还可以自己添加日志内容
引入Spring相关针对测试依赖
创建测试类,使用注解方式完成,不用每次都建立ioc容器,更加整洁
整合junit5 引入JUnit5jar包创建测试类还有简化版:
