一.spring
概念:
Spring是由Rod Johnson开发的一个开源容器框架,提供了控制反转[IoC],依赖注入,面向切面[AOP],事务管理,框架整合等功能,用于简化企业级应用开发.
特点:
1.轻量级:
Spring提供了许多服务,但这些服务默认关闭.同时,完整的Spring框架可以以在1M多大小的jar文件发布.
2.控制反转:
应用本身不负责依赖对象(被调用对象)的创建及维护,由外部容器负责依赖对象的创建及维护.
3.面向切面:
在运行时,动态的将代码切入到类的指定方法或位置上.
4.容器:
Spring包含并管理应用对象的配置和生命周期,因此Spring称为容器.
下载Spring:
官网地址:http://www.springsource.org/download
下载地址:https://repo.spring.io/libs-release-local/org/springframework/spring/
JDK与版本:
Spring Framework3.x: JDK5+
Spring Framework4.x: JDK6+
Spring Framework5.x: JDK8+
开发步骤:
第1步: 添加jar包
commons-logging-1.2.jar
spring-aop-5.1.2.RELEASE.jar
spring-beans-5.1.2.RELEASE.jar
spring-context-5.1.2.RELEASE.jar
spring-core-5.1.2.RELEASE.jar
spring-expression-5.1.2.RELEASE.jar
第2步: 创建Java类
创建1个实体类
备注: 测试Spring框架控制实体类[创建实体类,提供实体类对象]
第3步: 创建Spring配置文件
配置文件名称[beans.xml,application.xml,spring.xml,spring-bean.xml等等]任意,位置不限[src下].
配置文件模板位置[参考pdf或html]
第4步: 编写Spring配置文件
<bean>用于将指定位置的Java类,交给Spring容器管理[控制反转(帮你创建对象),依赖注入(向你提供对象)等等]
示例:
<bean class="bean.User" id="myuser" />
第5步: 测试程序
public static void main(String[] args) {
//读取配置文件
ApplicationContext app=new ClassPathXmlApplicationContext("配置文件名.xml");
//从Spring容器中获得1个对象
Object object= (Object ) app.getBean("id匿名");//Object-->User
user.setName("小白");
System.out.println(user);
}
二 .控制反转
概念:
控制反转[Inversion of Control]指应用本身不负责依赖对象(被调用对象)的创建及维护,由外部容器负责依赖对象的创建及维护.
控制反转实现方式:
第1种: 构造方法
<bean id="Bean匿名" class="类全名" />
![对象的构造函数](https://img-blog.csdnimg.cn/20210607231802196.png)
第2种: 工厂类的静态方法
<!-- Bean匿名=工厂类.静态方法名() -->
<bean id="Bean匿名" class="工厂类全名" factory-method="静态方法名"/>
![工厂类的静态方法](https://img-blog.csdnimg.cn/20210607231848352.png)
第3种: 工厂类的对象方法
<bean id="别名A" class="工厂类全名"/>
<bean id="别名" factory-bean="别名A" factory-method="方法名"/>
第4种: 注解方式
a.添加context命名空间和context约束文件的地址
b.添加<context:component-scan base-package="包名">
c.在相关类上添加注解:
注解: @Controller[标注在Action类上],@Service[标注在业务类上],@Repository,@Component[无法分辨层级,比如实体]
作用: 声明将当前类交给Spring容器管理.
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210607232838939.png)
三.依赖注入
概念:
依赖注入[Dependency Injection]指在运行期,由外部容器动态地将依赖对象[要使用的对象]注入到组件中.
注意: 依赖注入的前提是控制反转,被注入对象和接受注入的对象都必须被Spring容器管理.
依赖注入实现方式
方式1: setter方式
Java类:
private 普通属性类型 属性名;
private 自定义类类型 属性名;
private 集合类型 属性名;
//提供setter和getter
配置文件:
<bean id="Bean对象匿名" class="类全名">
<property name="属性名" value="值" />
<property name="属性名" ref="Bean对象匿名" />
<property name="属性名">
<list>\<value>
<set>\<value>
<map>\<entry>
<props>\<prop>
</property>
</bean>
//使用setter方式示例代码
<bean class="bean.Car" id="car"/>
<bean id="di_setter" class="bean.DI_Setter">
<!--1.setter方式-->
<!--普通数据-->
<property name="id" value="1"/>
<property name="name" value="小蜜瓜"/>
<property name="income" value="12000"/>
<property name="sex" value="女"/>
<property name="marry" value="true"/>
<!--对象数据-->
<property name="car" ref="car"/>
<!--集合数据-->
<property name="myList" >
<list >
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</list>
</property>
<property name="myMap">
<map>
<entry key="a" value="1"/>
<entry key="b" value="2"/>
<entry key="b" value="3"/>
</map>
</property>
<property name="mySet">
<set>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</set>
</property>
</bean>
方式2: 构造函数
Java类:
private 普通属性类型 属性名;
private 自定义类类型 属性名;
private 集合类型 属性名;
//提供有参构造方法
配置文件:
<bean id="Bean对象匿名" class="类全名">
<constructor-arg index="参数索引" value="值" />
<constructor-arg index="参数索引" type="类全名" ref="Bean对象匿名" />
<constructor-arg index="参数索引" >
<list/set/map/props>[参考setter方式]
</constructor-arg>
</bean>
//构造函数使用示例
<bean class="bean.Car" id="car"/>
<bean id="di_setter" class="bean.DI_Setter">
<!--1.构造函数方式-->
<!--普通数据-->
<constructor-arg name="id" value="1"/>
<constructor-arg name="name" value="小蜜瓜"/>
<constructor-arg name="income" value="12000"/>
<constructor-arg name="sex" value="女"/>
<constructor-arg name="marry" value="true"/>
<!--对象数据-->
<constructor-arg name="car" ref="car"/>
<!--list集合数据-->
<constructor-arg name="myList" >
<list >
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</list>
</constructor-arg>
<!---map集合数据-->
<constructor-arg name="myMap">
<map>
<entry key="a" value="1"/>
<entry key="b" value="2"/>
<entry key="b" value="3"/>
</map>
</constructor-arg>
<!--set方法-->
<constructor-arg name="mySet">
<set>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</set>
</constructor-arg>
</bean>
方式3: 注解方式
Java类与配置文件:
a.配置文件中context命名空间和context约束文件的地址
b.配置文件中添加<context:component-scan base-package=“包名” />
c.在Java类的属性或setter上添加注解: @Autowired或@Resource.
@Autowired:
格式: @Autowired [(required=true)]
说明:
1.编写在属性或setter上,表示将Spring容器中同类型的Bean对象赋给该属性
2.根据属性类型到Spring容器中寻找bean对象,然后注入依赖对象
3.required默认为true,即配置文件中必须有同类型的Bean对象,否则报错
@Resource:
格式: @Resource[(name=“Bean对象匿名”)]
说明:
1.编写在属性或setter上面,表示将Bean对象匿名对应的对象赋给该属性
2.name属性值为Bean对象匿名,表示将Bean对象匿名对应的对象赋给该属性
3.@Resource标注在setter上或不设置name属性,则name属性值默认为属性名
4.若未设置name属性,并且按照默认名称仍然找不到依赖对象时,@Resource将会按属性类型查找同类型的bean对象,然后注入到属性中.
方式4: P命名空间
Java类:
提供属性的setter和getter方法,无需其他操作.
配置文件:
第1步: 添加命名空间
xmlns:p=“http://www.springframework.org/schema/p”
第2步: 注册bean,并注入数据
<bean id=“bean匿名” class=“类全名” p:属性名/属性名-ref=“值/匿名” />
四.使用注解实现SpringAOP
面向切面编程:
面向切面编程[Aspect Oriented Programming,简称AOP]指在运行时,动态的将代码切入到类的指定方法或位置上的编程思想.
术语:
- aspect(切面): 指横切性关注点的抽象即为切面,它与类相似,类是对物体特征的抽象.[通俗讲,切面是定义了额外功能的类].
- joinpoint(连接点): 指被拦截的点,分为属性,方法,构造器.Spring只支持方法类型的连接点.[通俗讲,应用额外功能的地方称为连接点]
- pointcut(切入点): 指对"连接点"进行拦截的定义.[通俗讲,控制"哪些地方"应用切面]
- advice(通知): 指拦截到"连接点"之后所要做的事情.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知.
- target(目标对象): 指要使用切面的类.
- weave(织入): 指将"切面"应用到"目标对象"并导致"代理对象"创建的过程称为织入.
- introduction(引入): 在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或Field.
通知类型:
前置通知: 在目标方法执行之前,执行前置通知
后置通知: 在目标方法执行之后,执行后置通知
异常通知: 在目标方法执行并抛出异常时,执行异常通知
最终通知: 在目标方法执行之后或抛出异常时,执行最终通知
环绕通知: 在前置通知和目标方法之前,以及最终通知之前执行环绕通知
AOP通知执行过程
实现AOP方式
Spring提供了多种方式实现AOP,常用:(JDK动态代理和CGLIB代理)
方式一JDK动态代理:
使用Proxy类创建代理对象,含有处理类必须实现InvocationHandler接口.目标类必须实现接口[不限制类型],JDK动态代理通过实现目标类实现的所有接口,实现动态代理功能
方式二CGLIB代理:
使用Enhancer类生成代理对象,含有处理类必须实现MethodInterceptor接口.CGLIB通过生成目标类的子类,并重写目标类非final的方法实现动态代理功能
代理方式选择:
1.默认情况下,目标对象[被拦截的对象]必须实现了接口,Spring才会使用JDK动态代理.否则,Spring自动使用CGLIB代理
2.当目标对象实现了接口,可以设置aop:aspectj-autoproxy的proxy-target-class为true,强制使用CGLIB代理
使用注解方式实现AOP开发步骤:
第1步: 添加jar包
第2步:编写切面类,设置切入点和通知
- @Aspect: 编写在类声明上面,表示声明当前类为切面类
- @Pointcut: 编写在方法上面,定义切入点要求,"方法名()"即为切入点名
格式:@Pointcut(value = “execution(表达式)”)
表达式:
execution(返回值类型 目录.类名.方法名(参数类型,…) && args(参数名,参数名,…))
说明:
1.返回值类型为void或类型全名,可配合"!“使用.[!void表示有返回值]
2.任意返回值/任意类名/任意方法名,都可以用”“表示.
3.若包含指定目录的任意子目录,用”.“表示
4.参数类型为类全名.任意个数和类型用”…"表示
5.args()表示必须有指定个数的参数
示例:@Pointcut(value = "execution( service.UserService.*(…))")
- @Before :编写在方法上面,鄙视声明当前方法为前置通知
格式: @Before(value=“切入点名”,argNames=“参名,…”) - @AfterReturning: 编写在方法上面,表示声明当前方法为后置通知
格式: @AfterReturning(value=“切入点名”,return=“参数名[接收返回值]”) - @After: 编写在方法上面,表示声明当前方法为最终通知
格式: @After(value=“切入点名”) - @AfterThrowing: 编写在方法上面,表示声明当前方法为例外通知
格式: @AfterThrowing(value=“切入点名”,throwing=“参数名[接收异常对象]”) - @Around: 编写在方法上面,表示声明当前方法为环绕通知
格式: @Around(value=“切入点名”)
说明:
public Object 环绕通知(ProceedingJoinPoint point){
Object rs=point.proceed();//继续执行下1个通知或调用目标方法
return rs; //必须返回,否则后置通知无法获得目标方法返回值
}
定义切面类 在切面类中切入点上说明拦截目标 实现动态添加
@Component
@Aspect //声明当前类为切入类 切入类包含额外的方法
public class AOP {
//定义一个切入点
@Pointcut(value = "execution(* service.UserService.*(..))")
public void test(){
System.out.println("定义切入点:切入点为被标注的方法的名称");
}
//定义前置通知[用来拦截方法的参数]
@Before(value = "test() && args(p1) ",argNames = "p1")
public void qianzhitongzhi(Object p1){
System.out.println("前置通知");
System.out.println("拦截的方法参数"+p1);
}
//定义后置通知[用来拦截方法的返回值]
@AfterReturning(value = "test()",returning = "returnDate")
public void houzhitongzhi(Object returnDate){
System.out.println("后置通知");
System.out.println("被拦截的方法的返回值为"+returnDate);
}
@After("test()")
public void zuizhongtongzhi(){
System.out.println("最终通知");
}
//定义异常通知[用来拦截异常和打印异常信息]
@AfterThrowing(value = "test()",throwing = "e")
public void yichangtongzhi(Exception e){
System.out.println("异常通知");
System.out.println(e.getMessage());
}
//环绕通知
@Around("test()")
public Object huanraotongzhi(ProceedingJoinPoint point ) throws Throwable {
System.out.println("进入环绕通知");
Object ob = point.proceed();
System.out.println("离开环绕通知");
return ob;
}
}
注意: @Before,@AfterReturning,@After,@AfterThrowing,@Aroud默认属性为value[切入点名]
第3步: 开启aspectj自动代理,并注册切面类
<context:component-scan base-package="bean,service,aop"/<!--开启自动扫描并将有注释的类自动注册-->
<aop:aspectj-autoproxy/><!--启动AspectJ自动代理功能-->
第4步: 注册AOP
<!--注册切面类-->
<bean id="myaop" class="aop.MyAOP" />
或
@Component <!--若使用注释即可自动注册该类-->
第5步: 正常编写程序,测试AOP效果
使用XML方式实现AOP
步骤:
第1步: 添加jar包
同annotation方式
第2步: 编写切面类
同annotation方式,但是移除所有的注解[在配置文件中实现注解的功能].
/*@Component*/
@Aspect /*声明当前类为切入类 切入类包含额外的方法*/
public class AOP1 {
@Pointcut(value = "execution(* service.UserService.*(..))")
public void test(){
System.out.println("定义切入点:切入点为被标注的方法的名称");
}
@Before("test()")
public void qianzhitongzhi(){
System.out.println("前置通知");
}
@AfterReturning("test()")
public void houzhitongzhi(){
System.out.println("后置通知");
}
@After("test()")
public void zuizhongtongzhi(){
System.out.println("最终通知");
}
@AfterThrowing("test()")
public void yichangtongzhi(){
System.out.println("异常通知");
}
//环绕通知-
@Around("test()")
public Object huanraotongzhi(ProceedingJoinPoint point ) throws Throwable {
System.out.println("进入环绕通知");
Object ob = point.proceed();
System.out.println("离开环绕通知");
return ob;
}
}
第3步: 编写Spring配置文件
a.将切面类交给Spring管理
b.配置面向切面
<!--开启自动扫描-->
<context:component-scan base-package="bean,service,aop"/>
<aop:config>
<!--定义1个切面类-->
<aop:aspect id="myaop" ref="myAOP">
<!--定义1个切入点拦截service.UserService类中的所有方法(有参无参)-->
<aop:pointcut id="mycut" expression="execution(* service.UserService.*(..))"/>
<!--定义通知-->
<aop:before method="beforeDeal" pointcut-ref="mycut" arg-names="joinPoint" />
<aop:after-returning method="afterReturningDeal" pointcut-ref="mycut" returning="returnData"/>
<aop:after method="afterDeal" pointcut-ref="mycut" />
<aop:after-throwing method="afterThrowingDeal" pointcut-ref="mycut" throwing="e"/>
<aop:around method="aroundDeal" pointcut-ref="mycut" />
</aop:aspect>
</aop:config>
第4步: 编写程序,测试
同annotation方式
mybatis与spring框架整合
框架的作用:
MyBatis: 用于替代JDBC,用于数据持久化
Spring: 用于整合框架,提供整合功能及其他功能[IoC,DI,AOP,事务管理等等]
SpringMVC: 用于替代JSP,用于处理请求和响应[SpringMVC属于Spring的一部分]
Spring整合MyBatis:
MyBatis功能/操作: 配置文件[实体类别名,数据源,映射文件等等],映射文件[业务标签],MyBatis代码[SqlSessionFactory,SqlSession等对象操作]
Spring功能/操作: IoC,DI,AOP,事务管理
整合目标:
- 用Spring来替代MyBatis中的数据源,提供SqlSessionFactory,SqlSession等对象,管理事务
- .MyBatis整合中要做的内容: 配置文件[保留 实体类别名,映射文件等等],映射文件[业务标签]无变化,MyBatis代码[业务代码]
整合步骤:
第1步: 整合jar包
- MyBatis相关jar包:
mybatis-3.5.1.jar
log4j-1.2.17.jar - 数据库驱动器:
mysql-connector-java-5.1.22-bin.jar - Spring相关jar:
commons-logging-1.2.jar
spring-aop-5.1.2.RELEASE.jar
spring-beans-5.1.2.RELEASE.jar
spring-context-5.1.2.RELEASE.jar
spring-core-5.1.2.RELEASE.jar
spring-expression-5.1.2.RELEASE.jar - spring-jdbc-5.1.2.RELEASE.jar
spring-tx-5.1.2.RELEASE.jar - aopalliance-.jar
aspectjrt.jar
aspectjweaver.jar
cglib-nodep-2.1_3.jar - 额外jar:
连接池: commons-dbcp-1.4.jar,commons-pool-1.6.jar
MyBatis与Spring整合: mybatis-spring-2.0.3.jar
第2步: 整合配置文件
MyBatis配置文件:
mybatis-conf.xml[实体类别名,环境(数据源),加载映射],
log4j.xml[控制日志输出],映射文件[业务标签]
Spring配置文件: application.xml[控制反转]
整合后:
MyBatis配置文件中: 去掉环境配置(数据源),实体类别名,加载映射
log4j.xml[控制日志输出]: 无需操作
映射文件[业务标签]: 无需操作、
Spring配置文件中: 添加数据源,提供SqlSessionFactory,提供事务管理
1.开启自动扫描: 扫描service,action,mapper等等,实现控制反转[管理相关对象]---->注解方式实现控制反转
2.提供数据源
3.提供SqlSessionFactoryBean
4.提供事务管理 @@Transactional标注的类中所有关于数据库操作时,自动提交事务,以及回滚事务
5.注册其他必须的对象
第3步: 整合代码
MyBatis代码正常编写即可,若需要SqlSessionFactory对象可以从Spring容器中获得.
Mapper方式实现CURD:
1.Mapper接口: 正常编写
2.业务类: 声明Mapper接口类型的属性,并由Spring注入属性值
3.注册Mapper接口:
方式1: 指定加载某个1个Mapper接口
<bean class="org.mybatis.spring.mapper.MapperFactoryBean" id="mapperFactoryBean">
<property name="sqlSessionFactory" ref="factory" />
<property name="mapperInterface" value="mapper.UserMapper" />
</bean>
方式2: 指定加载某个包中的所有Mapper接口
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer" id="mapperScannerConfigurer" >
<property name="sqlSessionFactoryBeanName" value="factory" />
<property name="basePackage" value="mapper" />
</bean>