一、AOP演示
1.1 xml配置文件
1.1.1 导包
4 + 2 + 4
最后一个4
Spring的AOP包
spring-aspects-4.2.4.RELEASE.jar
spring-aop-4.2.4.RELEASE.jar
Spring需要的第三方AOP包
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
1.1.2 准备目标对象
package a_springaop;
// 切入点的类
public class UserServiceImpl implements UserService {
@Override
public void add() {
// 异常
int a = 1/0;
System.out.println("add");
}
@Override
public void delete() {
System.out.println("delete");
}
@Override
public void modify() {
System.out.println("modify");
}
@Override
public void find() {
System.out.println("find");
}
}
1.1.3 准备通知
- 前置通知:在切入点之前执行
- 后置通知:在切入点之后执行(无论有没有异常都执行)
- 环绕通知:切入点之前和之后都执行;如果遇到异常,之后的代码就不执行
- 异常通知:在切入点遇到异常后执行
- 后置通知:在切入点正常结束后才执行
package a_springaop;
import org.aspectj.lang.ProceedingJoinPoint;
// 通知类 - 基本了解
// 前置通知
// -在切入点之前执行
// 后置通知
// -在切入点之后执行(无论有没有异常都执行)
// 环绕通知 ProceedingJoinPoint
// 切入点之前和之后都执行
// 如果遇到异常,之后的代码就不执行
// 异常通知
// 在切入点遇到异常后执行
// 后置通知 afterReturning
// 在切入点正常结束后才执行
public class MyAdvice {
// 前置通知
public void before() {
System.out.println("前置通知");
}
public void after() {
System.out.println("后置通知1");
}
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕通知前");
// 执行原来方法
jp.proceed();
System.out.println("环绕通知后");
}
public void afterException() {
System.out.println("异常通知");
}
public void afterReturnning() {
System.out.println("后置通知2");
}
}
1.1.4 将通知织入到目标对象中
- 配置切入点
- 配置通知类
织入:添加新的命名空间:aop
aop:config
切入点配置:
aop:pointcut
- 配置方法:
expression
,expression="execution(* a_springaop.*ServiceImpl.*(..))"
- 切入点id:
id
- 配置方法:
- 配置切面:
aop:aspect
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- 1.配置切入点类 -->
<bean name="userService" class="a_springaop.UserServiceImpl"></bean>
<!-- 2.配置通知类 -->
<bean name="myAdvice" class="a_springaop.MyAdvice"></bean>
<!-- 3.织入 添加新的命名空间:aop -->
<aop:config>
<!-- 切入点配置:要增强的方法
void a_springaop.UserServiceImpl.add()
* a_springaop.UserServiceImpl.add()
* a_springaop.UserServiceImpl.*()
* a_springaop.*ServiceImpl.*()
* a_springaop.*ServiceImpl.*(..)
-->
<aop:pointcut expression="execution(* a_springaop.*ServiceImpl.*(..))" id="pc"/>
<!-- 配置切面 -->
<aop:aspect ref="myAdvice">
<aop:before method="before" pointcut-ref="pc"/>
<aop:after method="after" pointcut-ref="pc"/>
<aop:around method="around" pointcut-ref="pc"/>
<aop:after-throwing method="afterException" pointcut-ref="pc"/>
<aop:after-returning method="afterReturnning" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
</beans>
1.2 注解配置
1.2.1 导包(与配置文件一致)
1.2.2 准备目标对象(与配置文件一致)
1.2.3 准备通知(一定要在配置文件中开启注解)
使用注解之前,配置文件中开启注解
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
// 通知类 - 基本了解
// 前置通知
// -在切入点之前执行
// 后置通知
// -在切入点之后执行(无论有没有异常都执行)
// 环绕通知 ProceedingJoinPoint
// 切入点之前和之后都执行
// 如果遇到异常,之后的代码就不执行
// 异常通知
// 在切入点遇到异常后执行
// 后置通知 afterReturning
// 在切入点正常结束后才执行
// 使用注解之前,配置文件中开启注解
// <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <!-- 1.配置切入点类 --> <bean name="userService" class="b_annotationaop.UserServiceImpl"></bean> <!-- 2.配置通知类 --> <bean name="myAdvice" class="b_annotationaop.MyAdvice"></bean> <!-- 3.使用注解配置织入过程 --> <!-- 开启aop的注解配置 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
1.2.4 将通知织入目标对象中
package b_annotationaop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
// 通知类 - 基本了解
// 前置通知
// -在切入点之前执行
// 后置通知
// -在切入点之后执行(无论有没有异常都执行)
// 环绕通知 ProceedingJoinPoint
// 切入点之前和之后都执行
// 如果遇到异常,之后的代码就不执行
// 异常通知
// 在切入点遇到异常后执行
// 后置通知 afterReturning
// 在切入点正常结束后才执行
// 使用注解之前,配置文件中开启注解
// <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
@Aspect // 标志类是通知类
public class MyAdvice {
@Pointcut("execution(* b_annotationaop.*ServiceImpl.*(..))")
public void pc() {
// 方法唯一的用处就是为了承载注解
}
// 前置通知
@Before("MyAdvice.pc()")
public void before() {
System.out.println("前置通知");
}
@After("MyAdvice.pc()")
public void after() {
System.out.println("后置通知1");
}
@Around("execution(* b_annotationaop.*ServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕通知前");
// 执行原来方法
jp.proceed();
System.out.println("环绕通知后");
}
@AfterThrowing("execution(* b_annotationaop.*ServiceImpl.*(..))")
public void afterException() {
System.out.println("异常通知");
}
@AfterReturning("execution(* b_annotationaop.*ServiceImpl.*(..))")
public void afterReturnning() {
System.out.println("后置通知2");
}
}
二、Spring整合JDBC
2.1 Spring提供的DAO层模板
2.2 JdbcTemplate
功能与
DBUtils
的QueryRunner
类似//0. 准备连接池 ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setDriverClass("com.mysql.jdbc.Driver"); dataSource.setJdbcUrl("jdbc:mysql:///ssh"); dataSource.setUser("root"); dataSource.setPassword("root"); //1. 创建JDBC模板对象 JdbcTemplate jt = new JdbcTemplate(); jt.setDataSource(dataSource); //2. 书写sql,并执行 String sql = "insert into user values(null, 'rose')"; jt.update(sql);
2.3 步骤
2.3.1 导包
- 4 + 2:4个核心+2个日志
测试和切面需要的
- spring-test
- spring-aop
- junit4类库
数据库
- c3p0连接池
- JDBC驱动
事务
- spring-jdbc
- spring-tx事务
2.3.2 准备数据库
2.3.3 书写DAO
package c_jdbctemplate;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
public class UserDaoImpl implements UserDao {
private JdbcTemplate jdbcTemplate;
//增
@Override
public void addUser(User user) {
String sql = "insert into user values(null,?)";
jdbcTemplate.update(sql, user.getName());
}
//删
@Override
public void deleteUserById(int id) {
String sql = "delete from user where id = ?";
jdbcTemplate.update(sql, id);
}
//改
@Override
public void updateUser(User user) {
String sql = "update user where id=? and name=?";
jdbcTemplate.update(sql, user.getId(), user.getName());
}
//查全部
@Override
public List<User> findAll() {
String sql = "select * from user";
List<User> list = jdbcTemplate.query(sql, new RowMapper<User>() {
@Override
public User mapRow(ResultSet rs, int index) throws SQLException {
int id = rs.getInt("id");
String name = rs.getString("name");
User user = new User();
user.setId(id);
user.setName(name);
return user;
}
});
return list;
}
//查单个
@Override
public User getUser(int id) {
String sql = "select * from user where id = ?";
User user = jdbcTemplate.queryForObject(sql, new RowMapper<User>() {
@Override
public User mapRow(ResultSet rs, int index) throws SQLException {
int id1 = rs.getInt("id");
String name1 = rs.getString("name");
User user = new User();
user.setId(id1);
user.setName(name1);
return user;
}
}, id);
return user;
}
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}
2.3.4 Spring配置
- 逐层注入原理
因此要在配置文件中,都要注入。需要什么,注入什么
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <!-- 注册Dao --> <bean name="userDao" class="c_jdbctemplate.UserDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"></property> </bean> <!-- 注册jdbcTemplate --> <bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 注册DataSource --> <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql:///ssh"></property> <property name="user" value="root"></property> <property name="password" value="123456"></property> </bean> </beans>
2.3.5 测试
package c_jdbctemplate;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:c_jdbctemplate/applicationContext.xml")
public class JdbcTemplateDemo {
@Autowired
private UserDao ud;
@Test
public void test01() {
User user = new User();
user.setName("lucy");
ud.addUser(user);
}
@Test
public void test02() {
User user = ud.findUserById(1);
System.out.println(user);
}
@Test
public void test03() {
List<User> list = ud.findAll();
System.out.println(list);
}
}
2.4 进阶内容(JdbcDaoSupport)
2.4.1 原理
JdbcTemplate
的注入交给别人(JdbcDaoSupport
)来做,注入过程少了一个步骤
AccountDaoImpl
:继承JdbcDaoSupport
package d_transaction; import org.springframework.jdbc.core.support.JdbcDaoSupport; // JdbcDaoSupport已经包含了 JdbcTemplate public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { @Override public void decrement(int fromId, double money) { String sql = "update account set money = money - ? where id = ?"; // 调用父类的JdbcTemplate对象 getJdbcTemplate().update(sql, money, fromId); } @Override public void increment(int toId, double money) { String sql = "update account set money = money + ? where id = ?"; getJdbcTemplate().update(sql, money, toId); } }
配置文件中进行注册
<!-- 1.注册service --> <bean name="accountService" class="d_transaction.AccountServiceImpl" > <property name="ad" ref="accountDao"></property> </bean> <!-- 2.注册dao --> <bean name="accountDao" class="d_transaction.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 4.注册dataSource --> <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql:///ssh"></property> <property name="user" value="root"></property> <property name="password" value="123456"></property> </bean>
2.4.1 读取外部的Properties配置
外部配置文件:
db.properties
jdbc.driverClass=com.mysql.jdbc.Driver jdbc.jdbcUrl=jdbc:mysql:///ssh jdbc.user=root jdbc.password=root
配置文件中注意加前缀
context:
<!-- 1.引入src/db.properties配置文件 --> <context:property-placeholder location="classpath:db.properties"/> <!-- 3.注册dataSource --> <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverClass}"></property> <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property> <property name="user" value="root"></property> <property name="password" value="123456"></property> </bean>