Spring的第一天课程学习
Spring框架的概述以及Spring中基于XML的IOC配置
1.Spring的概述
❤spring是什么
Spring是分层的 Java SE/EE应用 full-stack 轻量级开源框架,以 IoC
(Inverse Of Control: 反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层 Spring MVC 和持久层 Spring JDBC 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多 著名的第三方框架和类库,逐渐成为使用最多的Java EE 企业应用开源框架。
❤spring的两大核心
❤spring的发展历程和优势
❤spring的体系结构
2.程序的耦合及解耦
曾经案例中的问题
工厂模式解耦
3.IOC概念和spring中的IOC
spring中基于XML的IOC环境搭建
4.依赖注入(Dependency Injection)
耦合
❤耦合:可以简单的理解为程序间的依赖关系
包括:
类之间的依赖
方法之间的依赖
❤解耦:降低程序间的依赖关系
实际开发中应该做到:
编译期不依赖,运行时才依赖。
❤解耦的思路
第一步;通过反射来创建对象,避免使用new关键字
第二步:通过读取配置文件来获取要创建对象的全限定类名
Bean
在计算机英语中,有可重用组件的含义
JavaBean
用java语言编写的可重用组件
Javabean的范畴远大于实体类
一个创建Bean对象的工厂,就是创建service和dao对象的
第一步:需要一个配置文件来配置我们的service和dao
配置的内容:唯一标识=全限定类名(key=value)
第二步:通过读取配置文件中的配置内容,反射创建对象
注:配置文件可以是xml也可以是properties
.newInstance();每次都会调用默认构造函数来创建对象
原来:我们获取对象时,都是采用new的方式,是主动的 现在:我们获取对象时,同时跟工厂要,有工厂为我们查找或者创建对象,是被动的,这种被动接收的方式获取对象的思想就是控制反转,他是Spring框架的核心之一。
控制反转
控制反转(Inversion of Control,英文缩写为IOC)把创建对象权利交给框架是框架的重要特征,并非面向编程的专业术语。
它包括依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup)
明确ioc的作用:
削弱计算机程序的耦合(接触我们代码中的依赖关系),
ApplicationContext的三个常用实现类:
❤ClassPathXmlApplicationContext:它可以加载类路径的配置文件,要求配置文件必须在类路径下。不在的话,加载不了
❤FileSystemXmlApplicationContext:它可以是加载磁盘任意路径下的配置文件(必须有访问权限)
❤AnnotationConfigApplicationContext:它是用于读取注解创建容器的
核心容器的两个接口引发的问题
❤ApplicationContet: 单例对象适用
它在创建核心容器时,创建对象采用的策略是采用立即加载的方式。也就是说,只要一读取完配置文件马上创建文件中的配置对象
❤BeanFactory: 多例对象适用
它在创建核心容器时,创建对象采取的策略是采用延迟加载的方式,也就是说,什么时候根据id获取对象了,什么时候才真正的创建对象。
spring对bean的管理细节
1.创建bean的三种方式
❤第一种方式:使用默认构造函数创建,
在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时。
采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建。
❤第二种方式:使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)
注;用到factory-bean 和factory-method
❤第三种方式:使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
2.bean对象的作用范围
bean标签的scope属性:
作用:用于指定bean的作用范围
取值:常用的是单例的和多例的
singleton;单例的(默认值)
prototype:多例的
request:作用于web应用的请求范围
session:作用于web应用的会话范围
global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境是,他就是session
3.bean对象的生命周期
单例对象
出生:当容器创建时对象出生
活着:只要容器还在,对象一直活着、
死亡:容器销毁,对象失望
总结:单例的生命周期和容器相同
多例对象
出生:当我们使用对象时spring框架为我们创建
活着:对象只要是在使用过程中就一直活着
死亡:当对象长时间不用,且没有别的对象引用时,由java的垃圾回收器回收
spring中的依赖注入
依赖注入:
Dependency Injection
Ioc的作用:
降级程序间的耦合(依赖关系)
依赖关系的管理:
以后都交给spring来维护
在当前类需要用到其他类的对象,有spring为我们提供,我们只需要在配置文件中说明
依赖关系的维护:
就称之为依赖注入
依赖注入:
能注入的数据:有三类
基本类型和String
其他bean类型(在配置文件或者注解配置过的bean)
复杂类型/集合类型
注入的方式:有三种
第一种:使用构造函数提供
第二种:使用set方法提供
第三种:使用注解提供
构造函数注入(一般不用)
使用标签:constructor-arg
标签出现的位置;bean标签的内部
标签的属性
type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中或某个参数的类型
index:用于指定要注入的数据给构造函数中指定索引的位置的参数赋值。索引的位置从0开始
name:用于指定给构造函数中指定名称的参数赋值 (常用)
--------------------------------------以上三个用于给构造函数中那个参数赋值--------------------------------------
value:用于提供基本类型和string类型的数据
ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的对象
优势:
在获取bean对象时吗,注入数据是必须的操作,否则对象无法创建成功。
弊端:
改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。
set方法注入(更常用的方式 )
涉及的标签:property
出现的位置:bean标签的内部
标签的属性
name:用于指定注入时所调用的set方法名称
value:用于提供基本类型和string类型的数据
ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的对象
优势:
创建对象时没有明确的限制,可以直接使用默认构造函数
弊端:
如果有某个成员必须有值,则获取对象是有可能set方法没有执行
复杂类型的注入/集合类型的注入
用于给List结构集合注入的标签
list array set
用于给Map结构集合注入的标签
map props
机构向他,标签可以互换
Spring第二天;spring基于注解的Ioc以及Ioc的案例
1.spring中的ioc的常用注解 2.案例使用xml方式和注解方式实现单标的CRUD操作
持久层技术选择:dbutils
3.改造基于注解的ioc案例,使用纯注解的方式实现
spring的一些新注解使用
4.sprijg和Junit整合
注解
1.属于创建对象的
❤他们的作用和在xml配置文件中编写一个<bean>标签实现的功能是一样的
@Component
作用:用于把当前类对象存如spring容器中
属性:
value:用于指定bean中的id。当我们不写是,他的默认值当前类名,且首字母改小写
注:需要在xml文件中告知spring容器在创建容器时要扫描的包,配置所需要的标签不是在beans的约束中
,而是一个名称为context名称空间和约束中
@Controller:一般用于表现层
@Service:一般用于业务层
@Repository:一般用于持久层
以上三个注解他们的作用和属性与Component是一模一样的,他们三个是spring框架为我们
提供明确的三层使用的注解,使我们的三层对象更加清晰
2.用于注入数据的
❤他们的作用和在xml配置文件中的bean标签中写一个<property>标签的作用是一样的
@Autowired:
作用:自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功、
如果ioc容器中没有任何bean的类型与要注入的变量类型匹配,则报错
出现位置;
可以上的变量上,也可以是方法上
细节:
在使用注解注入时,set方法就不是必须的了。
@Qualifier:
作用:在按照类中注入的基础之上再按照名称注入。它再给类成员注入时不能单独使用,但是再给方法参数注入时可以使用
属性:
value:用于指定注入bean的id
@Resource
作用:直接按照bean的id注入。他可以单独使用
属性:
name:用于指定bean的id
注:以上三个注入都只能注入其他bean类型的数据,而基本类型和string类型无法使用上述注解实现、另外
集合类型的注入只能通过xml来实现。
@Value
作用:用于用于注入基本类型和string类型的数据
属性:
value:用于指定数据的值。他可以使用spring中的SpEL(也就是spring中的EL表达式)
SpEL的写法:${表达式}
3.用于改变作用范围的
❤他们作用的集合在bean标签中使用scope属性实现的功能是一样的
@Scope
作用:用于指定bean的作用范围
属性:
value:指定范围的取值。常用取值:singleton prototype
4.和生命周期相关(了解)
❤他们的作用就和在bean标签中使用init-method和destory-method的作用是一样的
ProDestory
作用:用于指定销毁方法
PostConstruct
作用:用于指定初始化方法
spring中的新注解
Configuration
作用:指定当前类是一个配置类
细节:当配置类作为AnnotationConfigAppliContext对象创建的参数时,该注解可以不写
ComponentScan
作用:用于通过注解指定spring在创建容器时要扫描的包、
属性:
value:他和 basePackages的作用是一样的,都是用于指定创建容器时要扫描的包
Bean
作用:用于把当前方法的返回值作为bean对象存入spring的ioc容器中
属性:
name:用于指定bean的id。当不写时,默认值是当前方法的名称
细节;
当我们使用注解配置方法时,如果方法有参数,spring框架会去容器中查找有没有可用的bean对象。
查找的方式和Autowired注解的作用是一样的
Import
作用:用于导入其他的配置类
属性:
value:用于指定其他配置类的字节码
当我们使用Import的注解之后,有import注解的类是父配置类,而导入的都是子配置类
PropertySource
作用:用于指定properties文件的位置
属性:
value:指定文件的名称和路径
关键字:classpath,表示类路径下
spring整合junit问题分析
1.应用程序的入口
main方法
2.junit单元测试中,没有main方法也能执行
junit集成了一个main方法
该方法就会判断当前测试类中的那些方法有@Test注解
junit就让有Test注解的方法执行
3.junit不会管我们是否采用spring框架
在执行测试方法的时,junit根本不知道我们是否使用了spring框架
所以也就不会为我们读取配置文件/配置类创建spring核心容器
4有以上三点可知
当测试方法执行时,没有ioc容器,就算写了Autowired注解,也无法实现注入.
使用Junit单元测试,测试我们的配置
spring整合junit的配置
1.导入spring整合junit的jar坐标(spromg-test)
2.使用Junit提供的一个注解把原有的main方法给替换了,替换成spring提供的
@Runwith (SpringJUnit4ClassRunner.class)
3.告知spring的运行器,spring和ioc创建是基于xml还是 注解的,并说明位置
@ContextConfiguration
locations:指定xml文件的位置,加上classpath关键字,表示类路径下
classes:指定注解类所在的位置
当我们使用spring 5.x版本的时候,要求junit的jar必须是4.12及以上
spring学习第三天
多次操作使用一个事务:
需要使用ThreadLocal对象把Connection和当前线程绑定,从而使一个线程中只能有一个能控制事务的对象<
事务控制都应在业务层
动态代理:
特点:直接骂随用随创建,随用随加载
作用:不修改源码的基础上对方法增强
分类:
基于接口的动态代理
基于子类的动态代理
基于接口的动态代理:
涉及的类:proxy
提供者:JDK官方
如何创建代理对象:
使用Proxy类中的newProxyInstance方法
创建代理对象的要求:
被代理类最少实现一个接口,如果没有则不能使用
newProxyInstance方法的参数:
ClassLoader:类加载器
它是用于加载代理对象的字节码的。和被代理对象使用相同的类加载器。
固定写法:xxx.getClass().getClassLoader()
Class[ ]:字节码数组
它是用于让代理对象和被代理对象有相同的方法
固定写法;xxx.getClass().getInterfaces()
InvocationHandler 用于提供增强的代码
它是让我们写如何代理,我们一般都是一些该接口的实现类,通常情况下都是匿名内部类,但不是必须的
此接口的实现类都是谁用谁写
new InvocationHandler()
代码如下 /** * 动态代理: * 特点:字节码随用随创建,随用随加载 * 作用:不修改源码的基础上对方法增强 * 分类: * 基于接口的动态代理 * 基于子类的动态代理 * 基于接口的动态代理: * 涉及的类:Proxy * 提供者:JDK官方 * 如何创建代理对象: * 使用Proxy类中的newProxyInstance方法 * 创建代理对象的要求: * 被代理类最少实现一个接口,如果没有则不能使用 * newProxyInstance方法的参数: * ClassLoader:类加载器 * 它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法。 * Class[]:字节码数组 * 它是用于让代理对象和被代理对象有相同方法。固定写法。 * InvocationHandler:用于提供增强的代码 * 它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。 * 此接口的实现类都是谁用谁写。 / IProducer proxyProducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(), producer.getClass().getInterfaces(), new InvocationHandler() { /* * 作用:执行被代理对象的任何接口方法都会经过该方法 * 方法参数的含义 * @param proxy 代理对象的引用 * @param method 当前执行的方法 * @param args 当前执行方法所需的参数 * @return 和被代理对象方法有相同的返回值 * @throws Throwable / @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //提供增强的代码 Object returnValue = null; //1.获取方法执行的参数 Float money = (Float)args[0]; //2.判断当前方法是不是销售 if(“saleProduct”.equals(method.getName())) { returnValue = method.invoke(producer, money0.8f); } return returnValue; } }); proxyProducer.saleProduct(10000f); } }<
基于子类的动态代理(需要cglibjar包)
涉及的类:Enhancer
提供者:第三方cglib库
如何创建代理对象
使用Enhancer类中的create方法
创建代理对象的要求
被代理类不能是最终类
create方法的参数
Class字节码
它是用于指定被代理对象的字节码
Calback:用于提供增强的代码
我们一般写的都是该接口的子接口实现类:MethodInterceptor
Aop
1.什么是Aop
Aop:全称是Asopect Oriented Programming 即:面向切面编程 简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,再不修该源码的基础上,对我们已有的方法增强
2.Aop的作用及优势
作用:
在程序运行期间,不修改源码对已有的方法进行增强
优势:
减少重复代码
提高开发效率
维护方便
3 Aop的实现方法
使用动态代理技术
关于代理的选择 在spring中框架会根据目标类是否实现了接口来决定采用那种动态代理的方式
##AOP相关术语
Joinpoint(连接点): 方法
所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,
因为 spring 只支持方法类型的 连接点。
Pointcut(切入点): 被增强的方法
所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。
Advice(通知/增强):
所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。
通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
Introduction(引介):
引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方 法或 Field。
Target(目标对象):
代理的目标对象。
Weaving(织入):
是指把增强应用到目标对象来创建新的代理对象的过程。
spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。
Proxy(代理):
一个类被 AOP 织入增强后,就产生一个结果代理类。
Aspect(切面): 是切入点和通知(引介)的结合。
##学习spring中Aop要明确的事
a、开发阶段(我们做的)
编写核心业务代码(开发主线):大部分程序员来做,要求熟悉业务需求。
把公用代码抽取出来,制作成通知。(开发阶段最后再做):AOP 编程人员来做。
在配置文件中,声明切入点与通知间的关系,即切面。:AOP 编程人员来做。
b、运行阶段(Spring框架完成的) Spring 框架监控切入点方法的执行。
一旦监控到切入点方法被运行,使用代理机制,动态创建目标对 象的代理对象,
根据通知类别,在代理对象的对应位置,将通知对应的功能织入,
完成完整的代码逻辑运行。
spring中基于XML的AOP配置
1.把通知Bean也交给sring来管理 2.使用aop:config标签表明开始AOP的配置 3.使用aop:aspect标签表明配置切面 id属性:给切面提供一个唯一标识 ref属性:是指定通知类bean的id 4.在aop:aspect标签的内部使用对应标签来配置通知的类型 我们现在示例是让printLog方法在切入点方法执行之前执行:所以是前置通知 aop:before:表示前置通知 method属性:用于指定Logger类中的那个方法是前置通知 pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中那些方法的增强
切入点表达式的写法:
关键字:excution(表达式)
表达式:
访问修饰符 返回值 包名.包名.包名...类名.方法名(参数列表)
返回值可以使用通配符,表示任意返回值
包名可以使用通配符,表示任意包。但是有几级包,就需要写几个*
包名可以使用..表示当前包及其子包
类名和方法名都可以使用*来通配
* *..*.*()
参数列表
可以直接写数据类型
基本类型直接写名称 int
引用类型写包名·.类名的方式 java.lang.String
可以使用通配符表示任意类型,但是必须有参数
可以使用..表示有无参数均可,有参数可以是任意类型
全通配写法;
* *..*.*(..)
实际开发中切入点表达式通常写法:
切入到业务层实现类下的所有方法
* com.itheima.service.impl.*.*(..)
环绕通知; 问题: 当我们配置了环绕通知之后,切入点方法没有执行,而通知方法执行了 分析: 通过对比动态代理中的环绕通知代码,发现动态代理的环绕通知有明确的的切入点方法调用,而我们代码没有 解决: spring框架为我们提供了一个接口:ProceedingJionPoint。该接口有一个方法proceed(),此方法就相当于明确调用切入点方法。该接口可以作为环绕通知的方法参数,在程序执行时,spring框架会为我们提供该接口的实现类供我们使用
spring中的环绕通知: 它是spring框架为我们提供的一种可以在代码中手动控制增强方法何时执行的方式
spring第四天学习
JdbcTemplate的作用 他就是用于和数据库交互的,实现表的CRUD操作