目录
一、Spring基础
1.IoC和DI的思想
- 如果没有IoC(控制反转)和DI(依赖注入),调用者需要使用某个对象,其自身就得负责该对象及该对象所依赖对象的创建和组装;
- 通过IoC和DI的思想,就是将原本在程序中手动创建对象的控制权,交由Spring框架来管理;对象的管理和依赖注入交给框架去完成;
- IoC的实现方式:依赖注入(Dependency Injection,简称DI,最常用),还有一种方式叫“依赖查找”(Dependency Lookup)
- 注入的两种方式:构造方法注入、set方法注入
- spring配置的三种方式: 配置xml文件 、 注解方式annotation 、 使用Configuration注解代替xml文件(java Configuration);
2.getBean方法
- 按照bean的名字查找:world=(HelloWorld) factory. getBean ("helloWorld") ;
- 按照bean的类型查找:world = factory.getBean (HelloWorld.class) ;
- 按照名字和类型查找: (推荐):world=factory.gecBean ("helloWorld", HelloWorld.class) ;
3.Spring基本配置
- Bean中的id和name属性:spring3.1之后相同,可以起多个别名使用逗号或者空格分开;
- xml文件分割:使用<import resource = "classpath:cn/wolfcode/day1/02_hello/hello.xml"/>进行组合;
4.日志系统
- 日志分类:log4j、jcl、jul(jdk自带)、slf4j、logback、simple-log
- jcl:他不直接记录日志(抽象层),他是通过第三方记录日志优先原则匹配 log4j > jul 优先级
- slf4j:他也不记录日志(抽象层),通过绑定器绑定一个具体的日志记录来完成日志记录,log4j 、 jul、logback
spring4当中依赖的是原生的jcl,
spring5使用的spring的jcl(spring改了jcl的代码),采用优先原则匹配(默认绑定jul)
springboot使用slf4j抽象层
二、Ioc容器
1.Ioc容器
- BeanFactory: Spring最底层的接口,只提供了的IoC功能,负责创建、组装、管理bean;使用了懒加载,getBean时候才会初始化Bean;
- ApplicationContext接口:继承了BeanFactory,除此之外还提供AOP集成、国际化处理、事件传播、统一资源加载等功能;在初始化容器的时候就会初始化Bean;
1.1.bean实例化方式(需要使用@Autowired注解来声明)
- 构造器实例化(无参数构造器);
- 静态工厂方法实例化:解决系统遗留问题;
- 实例工厂方法实例化:解决系统遗留问题;
- 实现FactoryBean接口实例化;
ps:都需要在xml文件里进行设置;
1.2.bean作用域
- singlecon:单例,在Spcing IoC容器中仅存在一个bean实例(默认的scope);
- prototype:多例,每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行new XxxBean(): 会在容器启时创建对象;
- request:用于web开发,将Bean加入request范围,request.setAttribute("xxx"),在同一个reques获得同一个Bean;
- session:用于web开发, 将Bean放入Session范围,在同一个Session中获得同一个Bean;
- globalSession: 一般用于porlet应用环境,分布式系统存在全局session概念(单点登录),如果不是porlet环境,globalSession等同于Session;
1.3.bean的创建和销毁
- init-method: bean生命周期初始化方法,bean创建后会进行调用;
- destroy-method:容器被销毁的时候,如果bean被容器管理,bean销毁之前调用该方法;
ps:单例bean会执行销毁方法,多例bean是不会销毁容器的,因为bean可能有多个容器可能会再次创建(因为bean要往容器注册),造成资源浪费;
2.DI依赖注入
- 指Spring创建对象的过程中,将对象依赖属性(常量,对象,集合)通过设置值给该对象。
- 可以通过调用对象的setter方法.
- 可以在创建对象的时候(调用构造器),同时设置对象的属性值.
3.DI注解
使用@Autowired注解,是Spring规范提供的;
- Autowired注解寻找bean的方式:
- 首先按照依赖对象的类型找,如果找到就成功;
- 如果在Spring上下文中找到多个匹配的类型,再按照属性名字去找,如果没有匹配报错;
- 可以配合@Qualifier设置名称去查找;
使用@Resource注解(默认使用name进行查找,可以指定name和type属性),是JavaEE规范提供的;
4.IoC注解
使用@Component ("myDataSource") 组件如果不写value属性值,此时bean的id默认是类的首字母小写 ;
- 等价于<bean id="myDataSource" class="cn.wolfcode.ioc.MyDataSource"/ >,但是需要在xml进行IoC容器注解配置:<context:component-scan base-package="com.miaosha.*"/>
- 类似@Service,@Controller,@Repository注解,全部放在类上;@Component(泛指组件)
- 配置bean作用域需要加入@Scope ("prototype");
- 配置init和destroy方法需要在对应方法,加上注解@PostConstruct;@PreDestroy;
5.其他注解
- @Bean注解:用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理,需要配合@Configuration注解进行使用。
- @Autowired默认是根据类型进行注入的,因此如果有多个类型一样的Bean候选者,则需要限定其中一个候选者使用,在类的构造方法执行之后运行。
-
@PostConstruct 注解的方法将会在依赖注入完成后被自动调用,贴在方法上进行执行。
ps:执行的顺序Constructor >> @Autowired >> @PostConstruct
- @Qualifier注解在使用名称来进行限定。
- @Profile注解进行配置文件的区分符。
- @Configuration类似于@Component组件,里面可以包含注入依赖多个bean,相当一个bean。
ps:Component注解也会当做配置类,但是并不会为其生成CGLIB代理Class(可能new多个实例对象);Configuration会进行代理拦截从BeanFactory里获取创建好的实例(bean的作用域默认为单例)。
- @Primary当@Autowired的类型有多个实现类的时候,需要进行在类上声明一个主类,否则会报错。
- @ConfigurationProperties(prefix = "person")从properties文件配置属性。
-
@Value注解 ① ${ property : default_value } 从.properties文件获取 ② #{ obj.property? :default_value }从Bean对象获取
-
@Async注解标记的方法,在执行时会被AOP处理为异步调用,调用此方法处直接返回,@Async标注的方法使用其他线程执行。
-
@ConfigurationProperties,配置属性声明前缀,配上类的属性,在properties文件等地方可以进行赋值;
三、AOP面向切面
1.代理模式
- 客户端调用实际类,要对该调用进行增强可以通过代理类对调用进行拦截增强,代理类组合了实际类,让调用面向代理类而不是实际类;
- 客户端使用的都是代理对象而不是实际对象,通过代理类在客户端和实际对象之间起到中介的作用;
1.1静态代理
- 在程序运行前就已经存在代理类的字节码文件,代理对象和真实对象的关系在运行前就确定了。
1.2动态代理
- 在程序运行期间由JVM通过反射机制动态的生成(生成代理类,获取构造函数,通过构造函数new代理实例),代理对象和真实对象的关系是在程序运行时期才确定的
2.动态代理的实现
- 针对实际对象target实现了接口:使用JDK动态代理;(Advice增强代理类,实现reflect里的InvocationHandler接口,包含target要增强对象(实际对象))
- 原理:生成的代理类实现了实际对象的接口;
- 针对实际对象target没有接口无法实现:使用CGLIB或Javassist组件;(Advice增强代理类,实现cglib里的InvocationHandler接口,包含target要增强对象(实际对象))
- 原理:生成的代理类继承了实际对象;
3.AOP面向切面编程
-
OOP:面向对象的组合和继承可以一定程度消除重复,但是编程复杂代码耦合度大;
-
AOP:面向切面编程(横切关注点,比如:打日志、增加事务、权限验证等)来对原有对象功能的增强,它是通过动态代理来自动生成代理类并且可以避免一个功能点要被重复写很多遍,在OOP的基础上解脱编程复杂度,达到解耦合;
3.1专业术语:
- JoinPoint:需要被增强的方法,代表哪一个方法需要被增强;
- Pointcut:切入点,哪些方法需要被增强,是JoinPoint的一个集合(用表达式来进行匹配出JoinPoint);
- Advice:增强(通知),当拦截到JoinPoint后,在方法执行的某一时机(前置/后置/异常/最终/环绕增强)进行操作,进行增强;
- Aspect:切面=Pointcut+Advice(等价Advicor通知器),对很多个JoinPoint进行增强,形成一个切面;
- Target:目标对象,被代理的目标对象;
- Proxy:一个target类被AOP织入增强后,创建出来的代理对象;
- Weaving:织入,把Advice加到Target上,创建出来代理对象的过程;
- Advisor:通知器是一个特殊的切面,需要xml和java代码一块实现;切面可以只用xml配置;当使用注解时没有该概念;
ps:环绕增强代表前四个增强的合体(before,after,throw,finally);执行真实对象的方法,可以给增强方法传参ProceedingJoinPoint来获取被增强方法;
3.2Pointcut语法
- AspectJ 是一个面向切面的框架,AspectJ定义了AOP语法;spring只借鉴了AspectJ的语法并且一般情况springAOP够用,如果是第三方框架不能整合spring那么或许需要使用AspectJ;
- 括号中".."表示任意个参数,不带括号"xxx.."表示包含xxx以及xxx的任意子包,"*"代表一个单词;
- 比如:execution(* cn.volfcode.crm.service.*.*(..)) --- 代表(返回值 方法的全限定名(参数...))
- execution匹配精确到方法,within精确到类,args只匹配指定参数类型和指定参数数量的方法,与包名和类名无关
- @annotation匹配带有com.chenss.anno.xxx注解的方法,
- target匹配目标对象的类型,this匹配的是当前代理对象的类型(cglib的target和this是父子关系,jdk的是两个实现同一接口的类独立、不相干)
4.Spring的AOP开发
4.1配置xml文件:
- 配置Aspect切面(增强的方式)、配置要被增强的方法、配置方法增强的具体时机(前置/后置....;并且需要引用要被增强的方法);
4.2.注解配置:
- 使用IoC和DI的注解,可以去掉bean的声明;(需要在xml文件配置对应的注解解析器)
- 在类上使用@Aspect注解配置切面,使用@Pointcut获取到所有要被增强的方法(贴在方法上!),使用@Before等注解贴在增强的方式(需要引用pointcut要被增强的方法才可!)
- 最后配置AOP注解解析器<aop:aspectj-autoproxy/>;
4.3多例切面
- 默认的切面是单例的,尽管目标类是多例的也会是同一个代理类进行代理,可以配置切面prethis以及作用域
四、注解驱动开发
1.Bean注解介绍
@Configuration 配置类等价于xml配置文件,声明这是一个配置类(java config的配置方式)
@Bean 给容器注册一个Bean,class代表返回值的类型,id/name默认是用方法名,
@ComponentScan 配置包扫描的路径
让标注了@Controller 、@Service、@Repository、@Component的类被从指定路径扫描到,
支持重复注解@Repeatable使用@ComponentScans来组合多个ComponentScan ,
每个@Filter可以使用指定类型来进行过滤(自定义类型过滤跟标注的注解无关,只跟扫描的包路径有关),可以使用注解/正则/AspectJ表达式来进行过滤(不光跟包路径有关,还跟注解有关),
当类特别多还按照类路径扫描的话会非常慢,可以使用spring5的index给类构建索引来提高启动效率
@Scope 给Bean注解设置定义域,默认为单例且在容器创建时候创建Bean
@Lazy 懒加载在第一次获取的时候进行创建对象
ps:单例bean默认不为懒加载,多例bean默认为懒加载。
@Conditional 按照条件注册Bean,自定义的实现类需要实现Condintal接口的match方法
@Import 快速给容器导入一个Bean组件,id默认为组件的全类名 。
可以实现ImportSelector接口 返回需要导入的组件的全类名。
可以实现ImportBeanDefinitionRegistrar接口 自定义注册Bean
ps:实现FactoryBean接口可以创建一个Bean,配合@Bean注解可以实现,如果获取工厂Bean本身,需要 给id前加一个&。
2.Bean的生命周期
* 构造(对象创建)
* 单实例:在容器启动的时候创建对象
* 多实例:在每次获取的时候创建对象
*
* BeanPostProcessor.postProcessBeforeInitialization
* 初始化:
* 对象创建完成,并赋值好,调用初始化方法。。。
* BeanPostProcessor.postProcessAfterInitialization
* 销毁:
* 单实例:容器关闭的时候
* 多实例:容器不会管理这个bean;容器不会调用销毁方法;
3.Bean赋值
@Value 给字段进行赋值,可以写基本类型,可以使用EL表达式#{20-2},可以使用${}取配置文件的值,
@PropertySource ("classpath:/db.properties")给类声明配置文件的位置,可以使用PropertySources来声明多个PropertySource ,PropertySource 也可以指定多个值,
ps:最终配置文件里的信息都会在applicationContext环境里面。
@AutoWired 自动装配bean,不提供name和type参数,先按照type类型找如果有多个在按照属性name去找
用在字段上(较为常用)private SoakService soakService;
用在参数上 、用在构造方法上、用在set方法上
@Qualifier 可以明确指定要装配的bean,配合@AutoWired 使用
@Primary 进行自动装配的时候,默认使用首先的bean
@Resource 属于JSR规范(提供了name和type参数,默认按照name找,如果有多个按照type找;如果只指定一个找到多个或者找不到会报错 )
@Lookup 当单例bean依赖多例bean,因为单例只会初始化一次,这样会导致多例变为单例,可以调用方法时可以实现ApplicationContextAware接口重新getBean来解决,还可以使用该注解来解决
@Profile 动态的激活和切换一系列组件功能,指定组件在具体哪个环境下注册到容器中,不指定任何环境下都能注册这个组件
加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中,
指定命令行参数-Dspring.profile.active=test
使用代码的方式applicationContext.getEnvironment().setActiveProfiles(...)
4.AOP注解
@Pointcut 抽取公共的切入点(要被增强的方法)表达式
@Before/@After/@AfterReturning/@AfterThrowing/@Around 增强(通知)方法
@Aspect 当前类是一个切面类(包含切入点和增强/通知的类)
@EnableAspectJAutoProxy 给配置类(@Configuration)中激活动态代理
五、DAO持久化
1.事务
在一个事务方法中,调用了其他事务的方法,此时事务该如何传递,按照什么规则传播.
1.1事务传播规则情况一:需要遵从当前事务
- REQUIRED: 如果当前存在一个事务,则加入到该事务中,否则,新建一个事务;(使用比较多)
- SUPPORTS: 支持当前事务。如果当前存在事务,则使用该事务否则以非事务形式运行;
- MANDATORY: 必须要存在事务,如果当存在事务,就使用该事务,否则,抛出异常;
1.2事务传播规则情况二:不遵从当前事务
- REQUIRES_NEW:不管当前是否存在事务,都会新开启一个事务 必须是一个新的事务;(使用的比较多)
- NOT_SUPPORTED: 以非事务方式执行,如果当前存在事务,把当前事务暂停;
- NEVER :不支持事务,如果当前存在事务,抛出一个异常;
1.3事务传播规则情况三:寄生事务(外部事务/内部事务/嵌套事务)
- HESTED:寄生事务,如果当前存在事务,则在外部事务内执行;如果当前不存在事务则创建一个新的事务;
- 寄生事务可以通过数据库savePoint (保存点)来实现,寄生事务可以回滚的,但是他的回滚不影响外部事务.但是外部事务的回滚会影响寄生事务.
1.4<tx:method/>元素的属性(要被增强的方法)
- name:事务管理的方法名称,支持使用通配符方式:*匹配方法的模式
- propagation:事务的传播规则,默认REQUIRED
- isolation:事务的隔离级别,默认DEFAULT跟随数据表
- timeout:事务超时时间,默认跟随数据库
- read-only:是否是只读事务,针对查询操作
- rollback-for:遇到什么类型的异常做事务回滚,默认java.lang.RuntimeException
- no- rol lback-for:遇到什么类型的异常不回滚
2.事务的配置
- 基于xml:配置增强的方式、配置增强的一些设置以及对应的Joinpoint、配置切面增强和切入点Pointcut;
- 基于注解:配置@Transactional(该注解可以贴在类/方法上)在service类上,配置tx注解解析器和事务管理实际类(IOC和DI的注解解析器也得配置);