初识Spring
前言
Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。是一个轻量级框架,大大简化Java企业级开发。
Spring概念
设计理念
Spring是面向Bean(组件)的编程。将各种类型可以装配成Bean。并将之实例化。不需要程序员自己在代码上进行实例化。
优点
- 低侵入式设计
- 独立于各种应用服务器
- 依赖注入特性将组件关系透明化,降低了耦合度
- 面向切面编程特性允许将通用任务进行集中式处理
- 与第三方框架的良好整合
思想:
不在依赖自身的代码去获得所依赖的具体DAO对象,而是把这一工作交给了”第三方” - UserDaoFactory,从而避免了和具体实现类直接的耦合。
(1) 下载Spring并添加到项目中、如果使用Maven项目可直接引入依赖JAR包。
Spring官网的地址:http://repo.spring.io/release/org/springframework/spring/
下载所需要的版本Spring资源。
docs:该文件夹下包含Spring的相关文档,包括API参考文档、开发手册
libs:该文件夹存放Spring各个模块的jar文件。
schema:配置Spring的某些功能时需要用到的schema文件
(2) 编写Spring配置文件。
Spring的配置文件
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation://http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<!--通过bean元素声明需要Spring创建的实例。该实例的类型通过class属性指定,
并通过id属性为该实例指定一个名称,以便于访问-->
<bean id"helloSpring" class=cn.springdemo.HelloSpring">
<!--property元素用来为实例的属性赋值,此处实际是调用setWho()方法实现赋值-->
<property name="who">
<!--此处将字符串"Spring"赋值给who属性-->
<value>Spring</value>
</property>
</bean>
</beans>
(3) 编写代码通过Spring获取实例。
Spring IoC
控制反转(Inversion of Control , IoC),也称为依赖注入(Dependency Injection , DI),是面向对象编程中的一种设计理念,用来降低程序代码之间的耦合度。
控制权:Spring框架拥有创建类实例的权力 - 将创建类实例的权力反转到了Spring手里
Spring 依赖注入
setter访问器注入:
<bean id="唯一标识" class="类">
<property name="属性" value="值" index="下标"/>
</bean>
构造注入:
<bean id="" class="">
<constructor-arg ref="引用其他bean" index="下标" type="参数类型"/>
</bean>
注入不同数据类型:
使用<value>
标签 注意特殊字符的处理
引用Bean:使用ref 注意bean属性和local属性的区别使用内部bean:在<property>
标签中在添加一个<bean>
,使用权局限
注入list集合:
<property name="list">
<list>
<value>值</value>
<value>值</value>
</list>
</property>
注入array数组:
<property name="array">
<array>
<value>值</value>
<value>值</value>
</array>
</property>
注入set集合:
<property name="set">
<set>
<value>值</value>
<value>值</value>
</set>
</property>
注入map集合:
<property name="map">
<map>
<entry>
<key><value>key</value></key>
<value>值</value>
</entry>
</map>
</property>
注入properties:
<property>
<props>
<prop key="key">值</prop>
</props>
</property>
注入null和空字符串:
<null/>
特殊字符转义:
amp<![CDATA[转义的字符]]>
配置文件中 XSD | DTD
ApplicationContext atx =
new ClassPathXmlApplicationContext("applicationContext.xml");
atx.getBean();
Spring AOP
面向切面编程(Aspect Oriented Programming,AOP)软件编程思想发展到一定阶段的产物是对面向对象编程(Object Oriented Programming,OOP)的有益补充。
AOP一般适用于具有横切逻辑的场合,如访问控制、事务管理、性能监测等。
面向对象编程(Object Oriented Programming,OOP)补充。适用于具有横切逻辑的场合。
横切逻辑
一个典型的业务处理方法。日志、异常、事务、等都是一个健壮的业务系统必须的。但是为了保证系统健壮可用在众多业务方法中反复编写类似代码,使原本就很复杂的业务处理变得更复杂。业务功能的开发者还要关注这些”额外”代码是否处理正确,是否遗漏的地方。导致业务代码频繁而大量的修改。
业务中,一些散落,参透到系统各处且不得不处理的事情,这些穿插的既定业务中的操作就是所谓的”横切逻辑”,也称为切面。面向切面编程,简单的说是在不改变原程序基础上为代码段增加新的功能,对代码段进行增强处理。
面向切面编程的基本概念
- 切面(Aspect):一个模块化的横切逻辑(或称横切关注点),可能会横切多个对象。
- 连接点(Join Point):程序执行中的某个具体的执行点。
- 增强处理(Advice):切面在某个特定连接点上的代码逻辑。
- 切入点(Pointcut):对连接点的特征进行描述,可以使用正则表达式。增强处理和一个切入点表达式关联,并在与这个切入点匹配的某个连接点上运行。
- 目标对象(Target object):被一个或多个切面增强的对象。
- AOP代理(AOP proxy):由AOP框架所创建的对象,实现执行增强处理方法等功能。
- 织入(Weaving):将增强处理连接到应用程序中的类型或对象上的过程。
增强处理类型:
- 前置增强 - 在指定方法前织入方法
- 后置增强 - 在指定方法后织入方法
- 环绕增强 - 在目标方法的前后都可以织入增强处理。功能最强大的增强处理。环绕增强处理中,能获取或修改目标方法的参数、返回值,可以对它进行异常处理,甚至可以决定目标方法是否被执行。
- 抛出增强 - 在方法抛出异常时织入方法
- 最终增强 - 最终执行的方法,无论目标方法执行什么结果都会执行最终增强,类似finally作用,一般用于释放资源。可以为各个功能模块提供统一可以拔插的处理方案
切面可以理解为由增强处理和切入点组成,包含了横切逻辑定义也包含了连接点的定义。面向切面编程主要关系两个问题,即在什么位置,执行什么功能。
如何使用AOP切面
- 在xml配置文件中导入命名空间
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-cop-3.2.xsd
- 定义标签
<aop:config>
<aop:pointcut id="ID" expression="expression(public * show(com.entity.User))" /> - 切入点标签
<aop:aspect ref="bean"> - 引用指定的增强方法的bean
<aop:before method="方法名" pointcut-ref="切点ID"></aop:before> - 将方法定义为前置增强并引用至切入点
<aop:after-returning method="方法名" pointcut-ref="切入点ID" returning="" /> - 将方法定义为后置增强并引用至切入点,通过returning属性指定参数注入返回值
</aop:aspect>
<aop:after-throwing method="方法名" pointcut-ref="切入点ID" throwing="e" /> - 抛出异常时织入的指定方法引用至切入点,throwing指定参数名称
<aop:after method="方法名" pointcut-ref="切入点ID" /> - 方法定义最终增强并引用至切入点
<aop:around method="方法名" pointcut-ref="切入点ID" /> - 方法定义环绕增强引用至切入点
</aop:config>
使用注解方式定义切面
- 导入aspectj的jar包
- 配置XML-导入aop命名空间,添加
<aop:aspect-autoproxy/>
启用@AspectJ注解的支持。 - 使用注解@Aspect指定切面类、在通过相关的增强注解来增强方法。
@Aspect
public class UserServiceLogger {
//前置增强
@Before("execution(* cn.Test.*.*(..))")
public void Before(JoinPoint jp){
System.out.println("前置增强正在进行装备升级……");
}
//环绕增强
@Around("execution(* com.kuge.service.UserServiceImpl.*(..))")
public Object around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("调用"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法。方法入参:"
+ Arrays.toString(jp.getArgs()));
try{
Object result = jp.proceed();
System.out.println("调用"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法。方法返回值:"+result);
return result;
}catch (Throwable e){
log.error(jp.getSignature().getName()+"方法发生异常:"+e);
throw e;
}finally {
System.out.println(jp.getSignature().getName()+"方法结束执行。");
}
}
@AfterThrowing(value = "execution(* com.kuge.service.UserServiceImpl.*(..))",throwing = "e")
public void afterThrowing(JoinPoint jp, RuntimeException e){
log.error(jp.getSignature().getName()+"方法发生异常:"+e);
}
//后置增强
@AfterReturning(pointcut = "pointcut()",returning = "returnValue")
public void afterR(JoinPoint jp,Object returnValue){
System.out.println("后置增强被调用,返回值:"+returnValue);
log.info("调用"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法。方法返回值:"+returnValue);
}
//最终增强
@After("execution(* com.kuge.service.UserServiceImpl.*(..))")
public void after(JoinPoint jp){
System.out.println("调用"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法。最终增强");
}
}
public void *(com.entity.User) — *表示匹配所有方法名
public void show(..) — ..表示匹配所有参数个数和类型
* com.service..*(..) — 表示匹配所有com.service包下所有类所有方法
* com.service...*(..) — 表示匹配com.service包及其子包下所有类和方法