09 AOP
1、 面向切面编程
在软件业,AOP为aspect oriented programming 的缩写,面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术,AOP是OOP的延续,是软件开发中的一个热点,也是spring 框架中的一个重要内容,是函数式编程的一种衍生, 利用AOP可以对业务逻辑的各个部分惊醒隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP思想: 横向重复,纵向抽取
- 底层实现:
spring的 AOP 的底层用到两种代理机制:
JDK 的动态代理: 针对实现了接口的类产生代理
Cglib 的动态代理:针对没有实现接口的类产生代理,应用的是底层的字节啊增强的技术,生成当前类的子类对象
3.AOP 的开发中的相关术语
- joinpoint 连接点,指那些被拦截到的点,在spring 中,这些点指的是方法,因为spring只支持方法类型的连接点
- PointCut 切入点: 指我们要对哪些jointpoint 进行拦截的定义
- advice 通知: 拦截到jointpoint之后要做的事情就是通知,通知分为前置通知,后置通知,异常通知,最终通知,环绕通知
- introduction 引介: 一种特殊的通知在不修改类代码的前提下,introduction 可以在运行期为类动态地添加一些方法或Field
- aspect 切面是切入点和通知的结合
- target
- proxy
- weaving
插入在crud 中的事务处理代码就是切面
pointcut
public class UserServiceImpl implements UserService {
public void save() {
System.out.println("save");
}
public void delete() {
System.out.println("delete");
}
public void update() {
System.out.println("update");
}
public void select() {
System.out.println("select");
}
}
aspect
public class TransactionAdvice {
public void before(){
System.out.println("before");
}
public void after(){
System.out.println("after,this will be used no matter there is exception or not");
}
public void afterReturning(){
System.out.println("will not be used if there is exception");
}
public void afterException(){
System.out.println("will be used if there is exception");
}
public Object around(ProceedingJoinPoint point) throws Throwable {
System.out.println("before");
Object proceed = point.proceed();
System.out.println("after");
return proceed;
}
}
applicationContext.xml
<?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: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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean name="userService" class="com.leiqingqi.aop.service.UserServiceImpl"/>
<bean name="transactionAdvice" class="com.leiqingqi.aop.advice.TransactionAdvice"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.leiqingqi.aop.service..*ServiceImpl.*(..))"/>
<aop:aspect ref="transactionAdvice">
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
<aop:after-returning method="afterReturning" pointcut-ref="pointcut"/>
<aop:after-throwing method="afterException" pointcut-ref="pointcut"/>
<aop:around method="around" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>
test
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AOPTest {
@Autowired
private UserService userService;
@Test
public void testUpdate() {
userService.update();
}
@Test
public void testSave() {
userService.save();
}
}
10 AOP 注解开发
配置文件
<bean name="userService" class="com.leiqingqi.aop.service.UserServiceImpl"/>
<bean name="transactionAdvice" class="com.leiqingqi.aop.advice.TransactionAdvice"/>
<aop:aspectj-autoproxy/>
注解:
@Aspect
public class TransactionAdvice {
@Pointcut("execution(* com.leiqingqi.aop.service..*ServiceImpl.*(..))")
public void pointcut(){}
@Before("TransactionAdvice.pointcut()")
public void before(){
System.out.println("before");
}
@After("TransactionAdvice.pointcut()")
public void after(){
System.out.println("after,this will be used no matter there is exception or not");
}
@After("TransactionAdvice.pointcut()")
public void afterReturning(){
System.out.println("will not be used if there is exception");
}
@AfterThrowing("TransactionAdvice.pointcut()")
public void afterException(){
System.out.println("will be used if there is exception");
}
@Around("TransactionAdvice.pointcut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
System.out.println("before");
Object proceed = point.proceed();
System.out.println("after");
return proceed;
}
}
11 jdbcTemplate
导入jar包
spring-jdbc mysql-connector-java spring-tx spring-context mchange-commons-java c3p0
一个工具类,使用c3p0 缓冲池
public class DataSourceUtil {
public static JdbcTemplate getJdbcTemplate() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/blog1701?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false");
dataSource.setUser("root");
dataSource.setPassword("12345");
return new JdbcTemplate(dataSource);
}
}
可以设置applicationContext.xml 文件
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource;">
<property name="driverClass" value="${driver}"/>
<property name="jdbcUrl" value="${url}"/>
<property name="user" value="${username}"/>
<property name="password" value="${password}"/>
</bean>
<bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate;">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean name="blogDao" class="com.leiqingqi.dao.BlogDaoImpl">
<property name="jt" ref="jdbcTemplate"/>
</bean>
11.1 save
public int save(Blog blog) {
String sql = " insert into blog (title,author_id,state, featured, style) values (?,?,?,?,?)";
return jt.update(sql, blog.getTitle(), blog.getAuthorId(), blog.getState(), blog.getFeatured(), blog.getStyle());
}
11.2 delete
public int delete(Integer id) {
String sql = "delete from blog where id = ?";
return jt.update(sql, id);
}
11.3 update
public int update(Blog blog) {
String sql = "update blog set title = ?,author_id=?,state=?,featured=?,style=?";
return jt.update(sql, blog.getTitle(), blog.getAuthorId(), blog.getState(), blog.getFeatured(), blog.getStyle());
}
11.4 getById
public Blog getById(Integer id) {
String sql = "select * from blog where id = ?";
return jt.queryForObject(sql, new RowMapper<Blog>() {
public Blog mapRow(ResultSet resultSet, int index) throws SQLException {
return mapBlogHandler(resultSet);
}
}, id);
}
public Blog mapBlogHandler(ResultSet resultSet) throws SQLException {
Blog blog = new Blog();
blog.setId(resultSet.getLong("id"));
blog.setAuthorId(resultSet.getLong("author_id"));
blog.setFeatured(resultSet.getLong("featured"));
blog.setState(resultSet.getString("state"));
blog.setStyle(resultSet.getString("style"));
blog.setTitle(resultSet.getString("title"));
return blog;
}
11.5 getAll
public List<Blog> getAll() {
String sql = "select * from blog ";
return jt.query(sql, new RowMapper<Blog>() {
public Blog mapRow(ResultSet resultSet, int index) throws SQLException {
return mapBlogHandler(resultSet);
}
});
}
11.6 getAll
public List<Blog> getAll() {
String sql = "select * from blog ";
return jt.query(sql, new RowMapper<Blog>() {
public Blog mapRow(ResultSet resultSet, int index) throws SQLException {
return mapBlogHandler(resultSet);
}
});
}
11.7 getTotalCount
public int getTotalCount() {
String sql = "select count(1) from blog";
return jt.queryForObject(sql, Integer.class);
}
12 jdbcTemplate 使用注解
- 启动注解扫描
<context:component-scan base-package="com.leiqingqi.pojo" />
- 不用配置xml 文件中的daoImpl bean
- 在 dao层配置注解
@Repository("blogDao")
public class BlogDaoImpl implements BlogDao {
@Autowired
private JdbcTemplate jt;
}
13 事务管理
导包 spring-tx
xml:
<context:property-placeholder location="classpath:db.properties" />
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<property name="dataSource" ref="dataSource" ></property>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="transfer" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* com.leiqingqi.service..*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
14 事务管理注解
xml 开启注解
<tx:annotation-driven/>
service 层,事务管理管理的是service 层
只读事务只需要设置 read-only = "true"
就可以了
@Transactional(propagation = Propagation.REQUIRED,readOnly = false)
public void transfer(Integer from, Integer to, Double money) throws PropertyVetoException {
accountDao.subMoney(from, money);
int t = 9 / 0;
accountDao.addMoney(to, money);
}