Spring Aop基础
切面的五个通知,切点
1.通过注解
(1).将被代理类加入Ioc容器
(2).声明切面,并在切面中写需要使用的通知
把 LoggingAspect类声明为一个切面:需要把该类放到Ioc容器中,再声明为一个切面
多个切面之间: 可以使用@Order注解指定切面的优先级,值越小优先级越高
@Order(5)
@Aspect
@Component
public class LoggingAspect {
(3).在切面类中写需使用的通知
①.定义切点
/**
* 定义切点:定义一个方法,用于声明切入点表达式.一般地,该方法中再不需要添加其他代码.
* 使用@Pointcut声明切入点表达式.
* 后面的其他通知直接使用方法名来直接引用当前切入点表达式.
*/
@Pointcut("execution(public int AtithmeticCalculator.*(int ,int ))")
public void declare() {
}
②.前置通知
//前置通知:声明该方法是一个通知,在目标方法开始之前执行
@Before("declare()")
public void beforeMethod(JoinPoint joinPoint) {
//获取方法名
String methodName = joinPoint.getSignature().getName();
//获取方法传入的参数
List<Object> args = Arrays.asList(joinPoint.getArgs());
//打印日志
System.out.println("The method " + methodName + " begin with " + args);
}
③.后置通知
//后置通知:在目标方法执行后(无论是否发生异常)执行的通知和切点
@After("declare()")
public void afterMethod(JoinPoint joinPoint) {
//获取方法名
String methodName = joinPoint.getSignature().getName();
//获取方法传入的参数
List<Object> args = Arrays.asList(joinPoint.getArgs());
//打印日志
System.out.println("The method " + methodName + " after with " + args);
}
④.返回通知
/**
* 返回通知
* 返回通知可以访问方法的返回值
*
* @param joinPoint
* @param result:方法的返回值
*/
@AfterReturning(value = "declare()", returning = "result")
public void afterReturnMethod(JoinPoint joinPoint, Object result) {
//获取方法名
String methodName = joinPoint.getSignature().getName();
//获取方法传入的参数
List<Object> args = Arrays.asList(joinPoint.getArgs());
//打印日志
System.out.println("The method " + methodName
+ " afterReturning with " + args + " result:" + result);
}
⑤.异常通知
/**
* 异常通知
* 指定出现空指针异常才执行afterThrowingMethod方法:为public void afterThrowingMethod(JoinPoint joinPoint,NullPointerException ex) {}
*
* @param joinPoint
* @param ex 异常对象
*/
@AfterThrowing(value = "declare()", throwing = "ex")
public void afterThrowingMethod(JoinPoint joinPoint, Exception ex) {
//获取方法名
String methodName = joinPoint.getSignature().getName();
//获取方法传入的参数
List<Object> args = Arrays.asList(joinPoint.getArgs());
//打印日志
System.out.println("The method " + methodName + "afterThrowing with " + args + " Exception:" + ex);
}
⑥.环绕通知
// /**
// * 环绕通知
// * 环绕通知需携带ProceedingJoinPoint类型的参数
// * 环绕通知相当于动态代理全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法
// * 且环绕通知必须有返回值,返回值既为目标方法的返回值
// */
// @Around("execution( public int AtithmeticCalculator.*(int ,int ))")
// public Object aroundMethod(ProceedingJoinPoint pjd) {
// Object result = null;
// String methodName = pjd.getSignature().getName();
//
// try {
// //前置通知
// System.out.println("The method " + methodName + " begin with " + Arrays.asList(pjd.getArgs()));
// //执行目标方法
// result = pjd.proceed();
// //返回通知
// System.out.println("The method" + methodName + "return with " + result);
//
//
// } catch (Throwable e) {
// //异常通知
// System.out.println("The method" + methodName + " Exception:" + e);
// }
// //后置通知
// System.out.println("The method" + methodName + " after with"+ Arrays.asList(pjd.getArgs()) );
// return result;
// }
}
(3).在spring的配置文件中配置扫描注解,和使Aspectj 注解起作用;
<context:component-scan base-package="aop.imple"></context:component-scan>
<!--使Aspectj 注解起作用:自动匹配的类代理生成对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
2.基于配置文件的方式配置Aop
(1).定义切面类
package imple;
import org.aspectj.lang.JoinPoint;
import java.util.Arrays;
import java.util.List;
public class LoggingAspect {
public void beforeMethod(JoinPoint joinPoint) {
//获取方法名
String methodName = joinPoint.getSignature().getName();
//获取方法传入的参数
List<Object> args = Arrays.asList(joinPoint.getArgs());
//打印日志
System.out.println("The method " + methodName + " begin with " + args);
}
public void afterMethod(JoinPoint joinPoint) {
//获取方法名
String methodName = joinPoint.getSignature().getName();
//获取方法传入的参数
List<Object> args = Arrays.asList(joinPoint.getArgs());
//打印日志
System.out.println("The method " + methodName + " after with " + args);
}
public void afterReturnMethod(JoinPoint joinPoint, Object result) {
//获取方法名
String methodName = joinPoint.getSignature().getName();
//获取方法传入的参数
List<Object> args = Arrays.asList(joinPoint.getArgs());
//打印日志
System.out.println("The method " + methodName
+ " afterReturning with " + args + " result:" + result);
}
public void afterThrowingMethod(JoinPoint joinPoint, Exception ex) {
//获取方法名
String methodName = joinPoint.getSignature().getName();
//获取方法传入的参数
List<Object> args = Arrays.asList(joinPoint.getArgs());
//打印日志
System.out.println("The method " + methodName + "afterThrowing with " + args + " Exception:" + ex);
}
}
(2).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" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置Bean-->
<bean id="atithmeticCalculatorImpl" class="imple.AtithmeticCalculatorImpl"></bean>
<!--配置切面的Bean-->
<bean id="loggingAspect" class="imple.LoggingAspect"></bean>
<bean id="vlidationAspect" class="imple.VlidationAspect"></bean>
<!--配置Aop-->
<aop:config>
<!--配置切点表达式-->
<!--expression:要执行的目标方法
execution(目标方法)
目标方法:权限修饰符 返回值 那个包下那个类的那个方法
*:所有的
..所有的参数
-->
<aop:pointcut id="pointcut"
expression="execution(public int imple.AtithmeticCalculatorImpl.*(..))"></aop:pointcut>
<!--配置切面及其通知-->
<aop:aspect ref="loggingAspect" order="2">
<!--配置通知-->
<!--method:目标方法执行前或后或出异常所执行的方法-->
<!--pointcut-ref:引用切点-->
<aop:before method="beforeMethod" pointcut-ref="pointcut"></aop:before>
<aop:after method="afterMethod" pointcut-ref="pointcut"></aop:after>
<aop:after-returning method="afterReturnMethod"
pointcut="execution(public int imple.AtithmeticCalculatorImpl.*(int ,int ))"
returning="result"></aop:after-returning>
<aop:after-throwing method="afterThrowingMethod" pointcut-ref="pointcut" throwing="ex"></aop:after-throwing>
</aop:aspect>
<aop:aspect ref="vlidationAspect" order="1">
<aop:before method="validateArgs" pointcut-ref="pointcut"></aop:before>
</aop:aspect>
</aop:config>
</beans>
注意:假如某个类中的方法为某个切面通知的目标方法(这个类已经加进Ioc容器),则获取这个类的Bean时为代理类的对象,不是被代理类的对象
jdbcTempLate
属性配置文件
jdbc.user=root
jdbc.password=qq2694200519
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql:///spring3
jdbc.initPoolSize=5
jdbc.maxPoolSize=10
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"
xmlns:Context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool.xsd">
<Context:property-placeholder location="db.properties"></Context:property-placeholder>
<!--配置c3p0数据源-->
<bean id="DataSouce" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
</bean>
<!--配置spring的jdbcTempLate-->
<bean id="jdbcTempLate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="DataSouce"></property>
</bean>
</beans>
①.执行INSET,DELETE,UPDATE
@Test
public void textUpdate() {
String sql = "UPDATE book SET author= ? WHERE id=?";
jdbcTemplate.update(sql, "李一", 3);
}
②.执行批量更新,批量的INSET,DELETE,UPDATE
@Test
public void textBatchUpdate() {
String sql = "INSERT INTO trade (tradeTime,userId) VALUES(?,?)";
List<Object[]> batchArgs = new ArrayList<>();
for (int i = 0; i < 5; i++) {
batchArgs.add(new Object[]{new Date(), i});
}
jdbcTemplate.batchUpdate(sql, batchArgs);
}
③.从数据库中获取一条记录,实际上得到一个对象
/**
* 从数据库中获取一条记录,实际上得到一个对象
* 注意:不是调用queryForObject(sql,book.class,3)方法
* 而需调用queryForObject(String sql, RowMapper<T> rowMapper, Object... args)
* 1.RowMapper:指定如何去映射结果集的行,常用的实现类为BeanPropertyRowMapper
* 2.使用sql中列的别名完成列名和类属性名的映射,例如last_name lastName
* 3.不支持级联属性
*/
@Test
public void textQueryForObject() {
String sql = "SELECT id,author,title,price,publishingDate,salesAmount,storeNumber,remar remark FROM book WHERE id=?";
// book b =jdbcTemplate.queryForObject(sql,book.class,3);
RowMapper<book> rowMapper = new BeanPropertyRowMapper<>(book.class);
book b = jdbcTemplate.queryForObject(sql, rowMapper, 3);
System.out.println(b);
}
④.查询实体类的集合
/**
* 查询实体类的集合
* 注意,调用的不是queryForList方法
*/
@Test
public void textQueryForList() {
String sql = "SELECT id,author,title,price,publishingDate,salesAmount,storeNumber,remar remark FROM book WHERE id>?";
List<book> books = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(book.class), 1);
System.out.println(books);
}
⑤.获取单个列的值
/**
* 获取单个列的值,或做统计查询
* 使用queryForObject(String sql, Class<T> requiredType)
*/
@Test
public void textQueryForObject2() {
String sql = "SELECT COUNT(id) FROM book";
Long count = jdbcTemplate.queryForObject(sql, Long.class);
System.out.println(count);
}
NamedParameterJdbcTemplate
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"
xmlns:Context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool.xsd">
<Context:property-placeholder location="db.properties"></Context:property-placeholder>
<!--配置c3p0数据源-->
<bean id="DataSouce" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
</bean>
<!--使用NamedParameterJdbcTemplate需要配置jdbcTempLate-->
<bean id="jdbcTempLate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="DataSouce"></property>
</bean>
<!--配置NamedParameterJdbcTemplate,该对象可以使用具名参数,其没有无参数的构造器,所以必须为其构造器指定参数-->
<bean id="namedParameterJdbcTemplate"
class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg ref="DataSouce"></constructor-arg>
</bean>
<Context:component-scan base-package="tx"></Context:component-scan>
</beans>
使用具名参数
/**
* 使用具名参数时,可以使用update(String sql, SqlParameterSource paramSource)进行更新操作
* 1.sql语句参数名和类的属性必须一致!
* 2.使用SqlParameterSource接口的实现类BeanPropertySqlParameterSource作为参数
*/
@Test
public void testNamedParameterJdbcTemplate2() {
String sql = "INSERT INTO trade (tradeTime,userId) VALUES(:tradeTime,:userId)";
trade trade = new trade(new Date(),5);
SqlParameterSource parameterSource=new BeanPropertySqlParameterSource(trade);
namedParameterJdbcTemplate.update(sql,parameterSource);
}
或
/**
* 可以为参数起名字
* 好处:若有多个参数,则不用去对应位置,直接对应参数名,便于维护
* 缺点:较为麻烦
*/
@Test
public void testNamedParameterJdbcTemplate() {
String sql = "INSERT INTO trade (tradeTime,userId) VALUES(:tradeTime,:userId)";
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("tradeTime", new Date());
paramMap.put("userId", 8);
namedParameterJdbcTemplate.update(sql, paramMap);
}