一、基于 XML 的配置
1. IOC 中 bean 标签和管理对象细节
1.1 bean标签
作用:
用于配置对象让 spring 来创建的。
默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功。
属性:
id:给对象在容器中提供一个唯一标识。用于获取对象。
class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。
scope:指定对象的作用范围。
* singleton :默认值,单例的.
* prototype :多例的.
init-method:指定类中的初始化方法名称。destroy-method:指定类中销毁方法名称。
1.2 Spring 容器
在 Spring IOC 容器读取 Bean 配置创建 Bean 实例之前,必须对它进行实例化。只有在容器实例化后,才可以从 IOC 容器里获取 Bean 实例并使用。
1.2.1 Spring 提供了两种类型的 IOC 容器实现。
–BeanFactory: IOC 容器的基本实现。
–ApplicationContext: 提供了更多的高级特性. 是 BeanFactory 的子接口。(开发使用)
–BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;ApplicationContext 面向使用 Spring 框架的开发者,几乎所有的应用场合都直接使用 ApplicationContext 而非底层的 BeanFactory。
1.2.2 ApplicationContext
ApplicationContext 的主要实现类:
- ClassPathXmlApplicationContext: 它是从类的根路径下加载配置文件 推荐使用这种。
- FileSystemXmlApplicationContext: 它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
ApplicationContext 在初始化上下文时就实例化所有单例的 Bean。
1.2.3 从 IOC 容器中获取 Bean
调用 ApplicationContext 的 getBean() 方法
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-spel.xml");
Address address = (Address) ctx.getBean("address");
1.3 依赖注入
依赖注入:Dependency Injection。它是 spring 框架核心 ioc 的具体实现。
1.3.1 Spring 支持 3 种依赖注入的方式
–属性注入
属性注入即通过 setter 方法注入Bean 的属性值或依赖的对象
属性注入使用 <property> 元素, 使用 name 属性指定 Bean 的属性名称,value 属性或 <value> 子节点指定属性值
属性注入是实际应用中最常用的注入方式
–构造器注入
构造器注入在 <constructor-arg> 元素里声明属性
index:指定参数在构造函数参数列表的索引位置
type:指定参数在构造函数中的数据类型
value:它能赋的值是基本数据类型和 String 类型
–工厂方法注入(很少使用,不推荐)
1.3.2 引用其它 Bean
组成应用程序的 Bean 经常需要相互协作以完成应用程序的功能. 要使 Bean 能够相互访问, 就必须在 Bean 配置文件中指定对 Bean 的引用
通过 <ref> 元素或 ref 属性为 Bean 的属性或构造器参数指定对 Bean 的引用.
也可以在属性或构造器里包含 Bean 的声明, 这样的 Bean 称为内部 Bean
1.4 集合属性
1.4.1 List集合
1.4.2 Map集合
1.4.3 p命名空间
二、基于注解的配置方式
1. 在 classpath 中扫描组件
组件扫描(component scanning): Spring 能够从 classpath 下自动扫描, 侦测和实例化具有特定注解的组件。
1.1 特定组件
@Component: 基本注解, 标识了一个受 Spring 管理的组件
@Respository: 标识持久层组件
@Service: 标识服务层(业务层)组件
@Controller: 标识表现层组件
1.2 包扫描
当在组件类上使用了特定的注解之后, 还需要在 Spring 的配置文件中声明 <context:component-scan> :
- base-package 属性指定一个需要扫描的基类包,Spring 容器将会扫描这个基类包里及其子包中的所有类
- 当需要扫描多个包时, 可以使用逗号分隔
1.3 @Autowired 自动装配 Bean
自动按照类型注入。当使用注解注入属性时,set方法可以省略。它只能注入其他 bean 类型。当有多个类型匹配时,使用要注入的对象变量名称作为 bean 的 id,在 spring 容器查找,找到了也可以注入成功。找不到就报错。
1.4 加载 properties 配置文件
三、Spring AOP
1. AOP概述
1.1 什么是AOP
AOP:全称是 Aspect Oriented Programming 即:面向切面编程。
AOP 的主要编程对象是切面(aspect), 而切面模块化横切关注点.
简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的
基础上,对我们的已有方法进行增强。
案例:
需求1-日志:在程序执行期间追踪正在发生的活动
需求2-验证:希望计算器只能处理正数的运算
代码混乱:越来越多的非业务需求(日志和验证等)加入后,原有的业务方法急剧膨胀。每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点。
代码分散: 以日志需求为例,只是为了满足这个单一需求,就不得不在多个模块(方法)里多次重复相同的日志代码。如果日志需求发生变化,必须修改所有模块。
1.2 AOP术语
-
切面(Aspect): 横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象
- 通知(Advice): 切面必须要完成的工作
- 目标(Target): 被通知的对象
- 代理(Proxy): 向目标对象应用通知之后创建的对象
- 连接点(Joinpoint):程序执行的某个特定位置:如类某个方法调用前、调用后、方法抛出异常后等。
2. 基于注解的 AOP 配置
2.1 AspectJ 注解声明切面
要在 Spring 中声明 AspectJ 切面,只需要在 IOC 容器中将切面声明为 Bean 实例。
当在 Spring IOC 容器中初始化 AspectJ 切面之后,Spring IOC 容器就会为那些与 AspectJ 切面相匹配的 Bean 创建代理。
在 AspectJ 注解中, 切面只是一个带有 @Aspect 注解的 Java 类。
2.2 AspectJ 注解使用步骤
1) 导入jar包
spring-aspects-4.0.0.RELEASE.jar
spring-aop-4.0.0.RELEASE.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.net.sf.cglib-2.2.0.jar
2) 在配置文件中加入aop命名空间
3) 基于注解的方式
① 在配置文件中加入如下配置
② 把横切关注点的代码抽象到切面的类中
i. 切面首先是一个IOC中的bean,即加入@Component注解
ii. 切面还需要加入@Aspect注解
③ 在类中声明各种通知:
i. 声明一个方法
ii. 在方法前加入@before注解
④ 可以再通知方法中声明一个类型为JoinPoint的参数,然后就能访问链接细节,比如方法名称和参数值
2.3 代码实现
/**
* 定义一个方法,用于声明切入点表达式。一般该方法再不需要添入其他代码
* 使用@Pointcut 来声明切入点表达式
* 后面的其他通知直接使用方法名来引用当前的切入点表达式
*/
@Pointcut("execution(public int com.atguigu.spring.aop.ArithmeticCalculator.*(..))")
public void declareJointPointExpression(){ }
/**
* 在com.atguigu.spring.aop.ArithmeticCalculator接口的每一个实现类的每一个方法开始之前执行一段代码
*/
@Before("declareJointPointExpression()")
public void beforeMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("The method "+methodName+" begins with "+ Arrays.asList(args));
}
/**
* 在方法执行之后执行的代码,无论该方法是否出现异常
* @param joinPoint
*/
@After("declareJointPointExpression()")
public void afterMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println("The method "+methodName+" ends");
}
/**
* 在方法正常结束后执行的代码
* 返回通知是可以访问到方法的返回值的。
* @param joinPoint
*/
@AfterReturning(value = "declareJointPointExpression()",returning = "result")
public void afterReturning(JoinPoint joinPoint,Object result){
String methodName = joinPoint.getSignature().getName();
System.out.println("The method "+methodName+" ends with");
}
/**
* 在方法出现异常时会执行的代码
* 可以访问到异常对象,且可以指定在出现特定异常时在执行代码
* @param joinPoint
* @param ex
*/
@AfterThrowing(value = "declareJointPointExpression()",throwing = "ex")
public void afterThrowing(JoinPoint joinPoint,Exception ex){
String methodName = joinPoint.getSignature().getName();
System.out.println("The method "+methodName+" occurs excetion: "+ex);
}
3. 基于 XML 的 AOP 配置
3.1 步骤
1) 第一步:把通知类用 bean 标签配置起来
2) 第二步:使用 aop:config 声明 aop 配置
3)第三步:使用 aop:pointcut 配置切入点表达式
4)第四步:使用 aop:aspect 配置切面和通知
<!-- 1.配置bean -->
<bean id="arithmeticCalculator"
class="com.atguigu.spring.aop.xml.ArithmeticCalculatorLoggingImpl"></bean>
<!-- 配置切面的bean -->
<bean id="loggingAspect"
class="com.atguigu.spring.aop.xml.LoggingAspect"></bean>
<bean id="vlidationAspect"
class="com.atguigu.spring.aop.xml.VlidationAspect"></bean>
<!--2. 配置AOP -->
<aop:config>
<!--3. 配置切点表达式 -->
<aop:pointcut id="pointcut" expression="execution(* com.atguigu.spring.aop.xml.ArithmeticCalculator.*(int,int))"/>
<!--4. 配置切面及通知 -->
<aop:aspect ref="loggingAspect" order="2">
<aop:before method="beforeMethod" pointcut-ref="pointcut"/>
<aop:after method="afterMethod" pointcut-ref="pointcut"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="ex"/>
<aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/>
</aop:aspect>
<aop:aspect ref="vlidationAspect" order="1">
<aop:before method="validateArgs" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
3.2 通知说明
3.2.1 前置通知
3.2.2 后置通知
3.2.3 异常通知
3.2.4 最终通知
3.3 切入点表达式说明
execution:匹配方法的执行(常用)
execution(表达式) 表达式语法:execution([修饰符] 返回值类型 包名.类名.方法名(参数))
execution * com.atguigu.spring.ArithmeticCalculator.*(..)
匹配 ArithmeticCalculator 中声明的所有方法,第一个 * 代表任意修饰符及任意返回值.。第二个 * 代表任意方法, .. 匹配任意数量的参数.。
三、Spring中的 JdbcTemplate
1. JdbcTemplate 概述
它是 spring 框架中提供的一个对象,是对原始 Jdbc API 对象的简单封装。spring 框架为我们提供了很多的操作模板类。
操作关系型数据的: JdbcTemplate HibernateTemplate
操作 nosql 数据库的: RedisTemplate
操作消息队列的: JmsTemplate
2. JdbcTemplate 对象的创建
private JdbcTemplate jdbcTemplate;
{
jdbcTemplate = (JdbcTemplate) ctx.getBean("jdbcTemplate");
}
3. 配置数据源
第一步:导入数据库连接的配置文件
第二步:导入 c3p0 的jar包到工程的 lib 目录。在 spring 的配置文件中配置:
DBCP数据源配置:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"></bean>
spring 内置数据源:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"></bean>
4. JdbcTemplate 的增删改查操作
1.4.1 更新
update : public int update(String sql,Object args)
批量更新:public int[ ] batchUpdate(String sql,List<Object[ ]> batchArgs)
1.4.2 查询
查询单行
/**
* 从数据库中获取一条记录,实际得到对应的一个对象
* 调用 queryForObject(String sql,RowMapper<T> rowMapper,Object... args)
* 1.中的RowMapper 指定如何去映射结果集的行,常用的实现类为BeanPropertyRowMapper
* 2.使用sql中列的别名完成列名和类的属性名的映射
* 3.不支持级联属性,JdbcTemplate是一个JDBC的小工具,不是ROM框架
*/
@Test
public void testQueryForObject(){
String sql = "select id,last_name lastName,email from employees where id=?";
RowMapper<Employee> rowMapper = new BeanPropertyRowMapper<>(Employee.class);
Employee employee = jdbcTemplate.queryForObject(sql,rowMapper,1);
System.out.println(employee);
}
查询多行
/**
* 查到实体类的集合
*/
@Test
public void testQueryForList(){
String sql = "select id,last_name lastName,email from employees where id>?";
RowMapper<Employee> rowMapper = new BeanPropertyRowMapper<>(Employee.class);
List<Employee> employees = jdbcTemplate.query(sql,rowMapper,5);
System.out.println(employees);
}
单值查询
/**
* 获取单个列的值,或做统计查询
*/
@Test
public void testQueryForObject2(){
String sql = "select count(id) from employees";
long count = jdbcTemplate.queryForObject(sql,Long.class);
System.out.println(count);
}
5. dao 中使用 JdbcTemplate
5.1 在 dao 中定义 JdbcTemplate
给dao注入JdbcTemplate
配置dao
5.2 让 dao 继承 JdbcDaoSupport
四、 Spring中的事务控制
1. 基于 XML 的声明式事务控制
1.1 配置事务管理器
1.2 配置事务属性
1.3 配置事务切入点,以及把事务切入点和事务属性关联起来
2. 基于注解的事务
2.1 配置事务管理器并注入数据源
2.2 在业务层使用@Transactional 注解
@Transactional(propagation= Propagation.REQUIRES_NEW,
isolation = Isolation.READ_COMMITTED,readOnly = false,timeout = 3)
1. 使用 propagation 指定事务的传播行为:
即当前的事务方法被另外一个事务方法调用时如何使用事务,默认取值为REQUIRED,即使用调用方法的事务 REQUIRES_NEW 使用自己的事务,调用的方法的事务被挂起。
2. 使用 isolation 指定事务的隔离级别,最常用的取值为 READ_COMMITTED
3. 默认情况下Spring的声明式事务对所有的运行时异常进行回滚,也可以通过对应的属性进行设置,通常情况不进行设置
4. 使用 readOnly 指定事务是否为只读,表示这个事务只读取数据,但不更新数据,这样可以帮助数据库引擎优化事务,若真的是一个只读方法,应设置readOnly=true
5.使用 timeout 指定强制回滚之前事务可以占用的时间,秒为单位