关键词:AOP名词解释,AOP实现原理(动态代理)
AOP(Aspect-Oriented Programming:现象切面编程):将那些与业务无关的,却为业务模块所共同调用的逻辑(例如:事务处理、日志管理、权限控制等)封装轴取成一个可钟用的模块,这个模块被名为“切面”(Ascept),便于减少系统的重复代码,降低模块间得耦合度,并有利于未来的可拓展性和可维护性;
Spring AOP基于动态代理的实现:
如果被代理的对象,已经实现某个接口,则Spring AOP 会使用JDK Proxy(反射),基于接口的方式,创建代理的对象(JDK动态代理的核心是InvocationHandler接口和Proxy类);
如果被代理的对象,没有实现某个接口,就无法使用JDK Proxy去进行代理了,这时候Spring AOP会使用Cglib,基于继承的方式,生成一个被代理对象的子类来作为代理(cglib动态代理的核心是MethodInterceptor接口和Enhancer类);
切面:切点+通知
连接点:AOP将所有方法都是为连接点
切点:AOP可能被抽取共性功能的方法
通知: 在特定连接点上的动作
前置通知(Before)
返回通知(After-return)
异常通知(After-throwing)
后置通知(After)
环绕通知(Around)可代替以上四种
代理模式:(降低代码污染度)
功能:1.中介隔离作用
2.方法增强
方式:静态代理
动态代理:1.JDK自带
2.第三方Cglib
代理项目实现:
连接工具类
package com.ly.util;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class ConnectionUtil {
//装配数据源
DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
//创建线程区域对象
ThreadLocal<Connection> threadLocal=new ThreadLocal<Connection>();
//创建连接
public Connection CreateConn(){
Connection connection = threadLocal.get();
try {
if (connection==null){
connection = dataSource.getConnection();
threadLocal.set(connection);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return connection;
}
//关闭连接
public void getClose(){
threadLocal.remove();
}
}
事务处理类
package com.ly.util;
import java.sql.SQLException;
public class TransationUtil {
ConnectionUtil connectionUtil;
public void setConnectionUtil(ConnectionUtil connectionUtil) {
this.connectionUtil = connectionUtil;
}
//开启事务 设置自动提交事务开关为false
public void startTx(){
try {
connectionUtil.CreateConn().setAutoCommit(false);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
//提交事务
public void commitTx(){
try {
connectionUtil.CreateConn().commit();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
//回滚事务
public void rollbackTx(){
try {
connectionUtil.CreateConn().rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
//关闭事务
public void closeTx(){
try {
connectionUtil.CreateConn().close();
connectionUtil.getClose();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
业务层:
package com.ly.service;
import com.ly.dao.IAccountDao;
import com.ly.lazyton.Account;
import com.ly.util.TransationUtil;
import java.util.List;
public class AccountServiceImpl implements IAccountService{
IAccountDao dao;
//装配
TransationUtil transationUtil;
public void setTransationUtil(TransationUtil transationUtil) {
this.transationUtil = transationUtil;
}
public void setDao(IAccountDao dao) {
this.dao = dao;
}
public void save(Account account) {
dao.save(account);
}
public void update(Account account) {
dao.update(account);
}
public Account findName(String name) {
return dao.findName(name);
}
public List<Account> findAll() {
return dao.findAll();
}
public void transfer(String sourceName, String targetName, int money) {
try {
transationUtil.startTx();
Account sourceAccount = dao.findName(sourceName);
Account targetAccount = dao.findName(targetName);
sourceAccount.setAmoney(sourceAccount.getAmoney() - money);
targetAccount.setAmoney(targetAccount.getAmoney() + money);
dao.update(sourceAccount);
// int a= 10/0;
dao.update(targetAccount);
transationUtil.commitTx();
} catch (Exception e) {
e.printStackTrace();
transationUtil.rollbackTx();
}finally {
transationUtil.closeTx();
}
}
}
配置文件
<?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.xsd">
<bean id="pooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/kj?serverTimezone=GMT"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
</bean>
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg name="ds" ref="pooledDataSource"></constructor-arg>
</bean>
<bean id="connectionUtil" class="com.ly.util.ConnectionUtil">
<property name="dataSource" ref="pooledDataSource"></property>
</bean>
<bean id="transationUtil" class="com.ly.util.TransationUtil">
<property name="connectionUtil" ref="connectionUtil"></property>
</bean>
<bean id="daoimpl" class="com.ly.dao.AccountDaoImpl">
<property name="queryRunner" ref="queryRunner"></property>
<property name="connectionUtil" ref="connectionUtil"></property>
</bean>
<bean id="serviceimpl" class="com.ly.service.AccountServiceImpl">
<property name="dao" ref="daoimpl"></property>
<property name="transationUtil" ref="transationUtil"></property>
</bean>
<bean id="controllerimpl" class="com.ly.controller.AccountControllerImpl">
<property name="service" ref="serviceimpl"></property> </bean>
</beans>
日志通知实现
业务接口
public interface IAccountService {
public void save(int i);
public int delete();
public void update();
}
业务实现类
@Service
public class AccountServiceImpl implements IAccountService{
public void save(int i) {
System.out.println("===== 新增日志====="+i);
//int a=10/0;
}
public int delete() {
System.out.println("=====删除日志====");
return 0;
}
public void update() {
System.out.println("====修改日志===");
}
}
工具类
package com.ly.util;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* @author 李妍
* @version 1.0
* @since 2024/9/13
*/
@Component
@Aspect//切面
public class Logger {
@Pointcut("execution(public * com.ly.service.*.*(..))")
public void dian(){
}
/* @Before("dian()")
public void BeforeLogger(){
System.out.println("前置日志"); }
@AfterReturning("dian()")
public void returnLogger(){
System.out.println("返回日志");}
@AfterThrowing("dian()")
public void throwLogger(){
System.out.println("异常日志"); }
@After("dian()")
public void afterLogger(){
System.out.println("后置日志");}*/
@Around("dian()")
public Object roundLogger(ProceedingJoinPoint pjp){
Object obj=null;
try {
System.out.println("环绕==》前置日志");
obj=pjp.proceed(pjp.getArgs());
System.out.println("环绕==》返回日志");
} catch (Throwable e) {
e.printStackTrace();
System.out.println("环绕==》异常日志");
} finally {
System.out.println("环绕==》后置日志");
}
return obj;
}
}
主配置文件
<?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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--<bean id="service" class="com.ly.service.AccountServiceImpl"></bean>
<bean id="logger" class="com.ly.util.Logger"></bean>
<!– 配置aop–>
<Aop:config>
<!– 配置切面–>
<Aop:aspect id="aopAspect" ref="logger">
<!– 切点–>
<Aop:pointcut id="dian" expression="execution(public * com.ly.service.*.*(..))"/>
<!– 通知–>
<!– <Aop:before method="BeforeLogger" pointcut-ref="dian"></Aop:before>
<Aop:after-returning method="returnLogger" pointcut-ref="dian"></Aop:after-returning>
<Aop:after-throwing method="throwLogger" pointcut-ref="dian"></Aop:after-throwing>
<Aop:after method="afterLogger" pointcut-ref="dian"></Aop:after>–>
<Aop:around method="roundLogger" pointcut-ref="dian"></Aop:around>
</Aop:aspect>
</Aop:config>-->
<context:component-scan base-package="com.ly"></context:component-scan>
<!-- 注解版驱动-->
<Aop:aspectj-autoproxy></Aop:aspectj-autoproxy>
</beans>
结果如下: