了解spring框架
spring框架的出现,是为了解决企业开发的难度,减轻项目模块之间的管理,类和类之间的管理。帮助开发人员创建对象,管理对象之间的关系。
spring最核心的目的,就是将项目中成百上千的类管理起来,让某个类的变化对其他模块影响小,使得项目改动代价较小。也叫解耦合
IOC控制反转
控制反转:是一个理论,一种思想。将对象的创建、赋值、管理工作都交给代码之外的容器实现。也就是创建对象由外部资源实现
1、控制:创建对象。对象的属性赋值、对象之间的关系管理,全部由容器管理。
2、反转:以前创建对象,都是开发人员主动new对象,而反转,就是将原来开发人员创建对象的权限,转移给容器,由容器来创建对象,给对象赋值等工作。
总的来说,控制反转就是将创建对象、给对象赋值等工作,全部交给容器。
为什么要使用IOC:减少代码的改动,同时实现不同的功能。
- IOC的技术实现:
DI(依赖注入),是IOC的技术实现,此技术只需要提供所使用的对象名即可,其余都在容器内部实现
Spring的实现步骤
1、创建maven项目。
2、加入maven依赖
3、创建类(接口和实现类)
4、创建spring需要的配置文件,声明类的信息
<!--
<bean> :是根标签,代表一个java对象
声明beans,就是告诉spring要创建某个类的对象
<beans id=" " class=" ">
id:对象自定义名称,唯一值。
class:类的权限定名称
<bean xml:id="some" class="org.example.service.impl.someserviceImpl">
spring就完成了 someservice so = new someservice();
spring是把创建好的对象放进map:springmap.put(id的值,对象);
上面就是:springmap.put(some,new someservice())
-->
依赖注入
注入:就是赋值
依赖注入(di)的实现方法有两种:
1、在spring的配置文件中,用标签和属性完成那个。成为xml注入
2、在spring使用注解,完成属性赋值,称为注解注入
di的语法分类:
1、set(设置注入):spring调用set方法,在set方法中实现赋值。
2、构造注入:spring调用构造方法。
-
简单类型的set注入:
<bean id="xxx" class = "zzzz.xxxx.yyyy"> <property name = “name” value = 张湖屿”> <property name = "age" value ="23" > </bean> 一个property只能给一个属性赋值。 不管属性是什么类型,都必须放在双引号中
-
引用类型的注入:
首先如上,建立bean和property标签。 然后如下 <property name = "自定义名字" value ="bean的id" >
-
构造注入:
构造注入:spring调用类的带参构造方法,创建对象时给属性赋值,使用<constructor-arg>标签。 <constructor-arg>标签的构成: name:表示形参名。
<!--使用name属性实现构造注入--> <bean id="myStudent" class="com.bjpowernode.ba03.Student" > <constructor-arg name="myage" value="20" /> <constructor-arg name="mySchool" ref="myXueXiao" /> <constructor-arg name="myname" value="周良"/>
index:表示构造方法的参数的位置。 value:形参类型是简单类型,使用value ref:形参是引用类型,使用ref
-
自动注入
spring可以根据某些规则,自动给引用类型赋值。常用的有BName和ByType 1、byname:引用类型的属性名和< bean>标签的id值是一样的且数据类型相同,这样容器 中的bean就会自动赋值 语法如下 <bean id = "xxx" class = " qqq.www.eee" autowire = "byname"> 2、bytype:引用类型的数据类型和< bean>标签的class属性是同源关系。 同源:意为一类 情况如下: 1、引用类型的数据类型和bean标签的class是一样的 2、引用类型的数据类型和bean标签的class是父子关系 3、引用类型的数据类型和bean标签的class是接口和实现类的关系 语法如下 <bean id = "xxx" class = " qqq.www.eee" autowire = "bytype">
注解【重量级一定要掌握】
-
使用注解的步骤
1、加入maven依赖:spring-context,再加入此依赖同时,会加入spring-aop依赖,有aop依赖才能使用注解 2、加入注解(多个注解多个功能) 3、在spring标签中,加入扫描标签,说明注解在项目中的位置
-
spring中扫描多个包的方式:
1、多次使用组件,扫描不同的包: <context:component-scan base-package="com.zhy.ba01"/> <context:component-scan base-package="com.zhy.ba02"/> 2、使用分隔符(;或者,) <context:component-scan base-package="com.zhy.ba01";"com.zhy.ba01"/> 3。指定父包 比如例子的父包是zhy <context:component-scan base-package="com.zhy"/>
-
value注解
@value注解:简单类型的赋值 value是string类型的,所以无论什么值都要放在双引号内 位置: 1、属性定义的上面,无需set方法(推荐) public class Student { @Value("张宏宇") private String name; @Value("24") private Integer age; } 2、在set方法上
-
如何选择xml配置文件还是使用注解:
xml适合经常修改的文件,但是代码量较大。开发中代码和数值的关系没有那么清晰
注解比较方便,快捷。但是注解不适合经常改动的文件
AOP
-
动态代理:
实现方式: 1、jdk动态代理,使用jdk中的proxy、method、invocationhandler创建代理对象,jdk动态代理要求目标必须实现接口。 2、cjlib:第三方工具库,创建代理对象,原理是继承,通过继承目标类,创建子类,子类就是代理对象
-
动态代理的作用:
1、在源代码不改变的情况下增加功能 2、专注业务逻辑代码 3、解耦合
-
aop面向切面编程
基于动态代理,可以使用jdk和cjlib方法。aop就是将动态代理的步骤规范化 切面:给目标类增加功能,称为切面。切面最大的特点,就是和业务逻辑无关
-
如何理解面向切面
1、在分析项目功能时找出切面 2、合理安排切面执行在方法前还是后 3、合理安排切面在哪个方法前后
-
一个切面有三个重要因素:
1、切面的功能代码,切面干什么 2、切面执行的位置。使用pointcut声明执行的位置 3、切面的执行时间,用advice声明。
-
AOP的实现:
虽然spring在内部有实现了aop的规范,但是过于笨重。在开发中常用aspectJ框架。 aspectJ实现有两种方式: 1、使用xml文件配置的方式 2、使用注解。一般常用五个注解
aspectJ的使用
-
切面的执行时间
这个执行时间在aspectJ中称为advice,在aspectj框架中使用注解去表示 1、@before:前置通知注解 属性:value,是切入点表达式,表示切面执行的位置 位置:方法上面 特点:在目标方法前执行 不会改变目标方法的结果 不会影响目标方法的执行 2、@afterreturning 3、@around 4、afterThrowing 5、@after
-
表示切面执行位置的表达式:
execution(访问权限,方法返回值,方法声明(参数),异常类型) 常用符号:* :表示零到多个任意字符 .. :用在方法参数中,表示任意多个参数 用在包名后,表示当前包名及其子包路径 例如:execution(public * * (..)):切入点为任意公共方法
-
@Aspect
@Aspect : 是aspectj框架中的注解。 作用:表示当前类是切面类。 切面类:是用来给业务方法增加功能的类,在这个类中有切面的功能代码 位置:在类定义的上面 定义方法,方法是实现切面功能的。
- 方法的定义要求:
1.公共方法 public 2.方法没有返回值 3.方法名称自定义 4.方法可以有参数,也可以没有参数。如果有参数,参数不是自定义的,有几个参数类型可以使用。
-
后置、环绕通知:
后置通知AfterReturning有两个属性 1、value 切入点表达式 2、returning:自定义变量,表示方法返回值,必须和方法形参名字一样 位置: 在方法的上面 特点: 在目标方法之后执行 可以根据返回的值,做不同的处理 方法的定义要求: * 1.公共方法 public * 2.方法没有返回值 * 3.方法名称自定义 * 4.方法有参数的,推荐是Object ,参数名自定义 @AfterReturning(value = "execution(* *..SomeServiceImpl.doOther(..))", returning = "res") public void myAfterReturing( Object res ){ }
-
环绕通知:
语法格式: 1、public类型 2、必须有返回值,推荐object 3、方法名自定义 4、方法固定参数procedingJoinPoint
Spring框架提供事务的解决方案
###1、适用于中小项目的解决方案:注解
spring框架自己用aop实现了给业务增加事务的功能,使用@transactional注解增加事务
步骤如下:
① 声明事务管理器对象
<bean id = "xxxxx" class = " ">
② 开启事务注解驱动
使用aop机制,创建@transactional所在的类代理对象,使用aop的环绕通知
在xml中配置事务
<!--声明式事务处理:和源代码完全分离的-->
<!--1.声明事务管理器对象-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="myDataSource" />
</bean>
<!--2.声明业务方法它的事务属性(隔离级别,传播行为,超时时间)
id:自定义名称,表示 <tx:advice> 和 </tx:advice>之间的配置内容的
transaction-manager:事务管理器对象的id
-->
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<!--tx:attributes:配置事务属性-->
<tx:attributes>
<!--tx:method:给具体的方法配置事务属性,method可以有多个,分别给不同的方法设置事务属性
name:方法名称,1)完整的方法名称,不带有包和类。
2)方法可以使用通配符,* 表示任意字符
propagation:传播行为,枚举值
isolation:隔离级别
rollback-for:你指定的异常类名,全限定类名。 发生异常一定回滚
-->
<tx:method name="buy" propagation="REQUIRED" isolation="DEFAULT"
rollback-for="java.lang.NullPointerException,com.bjpowernode.excep.NotEnoughException"/>
<!--使用通配符,指定很多的方法-->
<tx:method name="add*" propagation="REQUIRES_NEW" />
<!--指定修改方法-->
<tx:method name="modify*" />
<!--删除方法-->
<tx:method name="remove*" />
<!--查询方法,query,search,find-->
<tx:method name="*" propagation="SUPPORTS" read-only="true" />
</tx:attributes>
</tx:advice>
<!--配置aop-->
<aop:config>
<!--配置切入点表达式:指定哪些包中类,要使用事务
id:切入点表达式的名称,唯一值
expression:切入点表达式,指定哪些类要使用事务,aspectj会创建代理对象
com.bjpowernode.service
com.crm.service
com.service
-->
<aop:pointcut id="servicePt" expression="execution(* *..service..*.*(..))"/>
<!--配置增强器:关联adivce和pointcut
advice-ref:通知,上面tx:advice哪里的配置
pointcut-ref:切入点表达式的id
-->
<aop:advisor advice-ref="myAdvice" pointcut-ref="servicePt" />
</aop:config>