AOP:面向切面编程,AOP编程可不是Spring独有的,Spring只是支持AOP编程的框架之一
作用:在程序运行期间,不修改源码对已有方法增强。
优势:减少重复代码;提高开发效率;维护方便
主要功能:日志记录、性能统计、安全控制、事务处理、异常处理等。
Spring AOP默认使用JDK动态代理作为AOP代理,这使得任何接口都可以被代理,也可以使用cglib代理。
在springAop中:
前置通知:调用目标方法之前织入的内容
后置通知:调用目标方法之后织入的内容
异常通知:在catch语句块中织入的内容
最终通知:finally语句块中织入的内容
环绕通知:整个invoke方法执行的过程,称为环绕通知
joinpoint:连接点:动态代理能访问的点(方法)
pointcut:切入点:需要被增强的点(方法)
Aspect(切面):切入点(要增强的方法)与通知(如何增强)之间的关系
案例:之前学习JDBC的时候我们接触到了事务,A账户给B账户转钱,我们需要加入事务的操作,
要满足事务的一致性!!
如果用代理模式来完成对事务的织入,程序如何写?
持久层:
/**
* @author shizi 2022/1/27
*/
@Repository
public class AccountDaoImpl implements AccountDao {
private Connection connection = JDBCUtils.getConnection();
private PreparedStatement preparedStatement = null;
/**
*
* A账户进行转账
*/
@Override
public void transfer() {
try {
preparedStatement = connection.prepareStatement("update test_account set banlance_A = banlance_A-? where id = ?");
preparedStatement.setDouble(1,1000);
preparedStatement.setInt(2,1);
int i = preparedStatement.executeUpdate();
System.out.println(i == 1 ?"A账户扣钱成功":"A账户扣钱失败");
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 给B账户加钱
*/
@Override
public void saveAccount() {
try {
preparedStatement = connection.prepareStatement("update test_account set banlance_B = banlance_B+? where id = ?");
preparedStatement.setDouble(1,1000);
preparedStatement.setInt(2,1);
int i = preparedStatement.executeUpdate();
System.out.println(i == 1 ?"B账户加钱成功":"B账户加钱失败");
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
AffairsUtils.closeAffairs();
}
}
}
业务层:
@Service("service")
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
public void saveAccount() {
accountDao.saveAccount();
}
@Override
public void transfer() {
accountDao.transfer();
}
}
代理类:
/**
* @author shizi 2022/2/3
* 为业务层做代理
*/
@Component
public class AccountProxy {
/**
* 目标对象
*/
@Autowired
private AccountService accountService;
/**
* 获取代理对象
* @return
*/
public Object getProxy(){
return Proxy.newProxyInstance(accountService.getClass().getClassLoader(), accountService.getClass().getInterfaces(), new InvocationHandler() {
/**
* 完成对目标方法的增强:
*
* 在springAop中:
* 前置通知:调用目标方法之前织入的内容
* 后置通知:调用目标方法之后织入的内容
* 异常通知:在catch语句块中织入的内容
* 最终通知:finally语句块中织入的内容
* 环绕通知:整个invoke方法执行的过程,称为环绕通知
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = null;
try {
if(method.getName().equals("transfer")){
AffairsUtils.beginAffairs();
}
//调用目标类方法
invoke = method.invoke(accountService, args);
if(method.getName().equals("saveAccount")){
AffairsUtils.commitAffairs();
}
}catch (Exception e){
//回滚事务
AffairsUtils.rollbackAffairs();
e.printStackTrace();
}finally {
if("saveAccount".equals(method.getName())){
AffairsUtils.closeAffairs();
}
}
return invoke;
}
});
}
}
测试类:
public class AopTest01 {
private static ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
public static void main(String[] args) {
//从容器中获取代理对象
AccountProxy accountProxy = applicationContext.getBean("accountProxy", AccountProxy.class);
AccountService proxy = (AccountService)accountProxy.getProxy();
proxy.transfer();
proxy.saveAccount();
}
}
工具类:
JDBCUtils
/**
* @author shizi 2022/2/2
* 为了使得数据库相关对象是单例的,所以重新封装工具类
*/
@Component
@Configuration
@PropertySource("classpath:jdbc")
public class JDBCUtils {
private static Connection connection;
private static String username = "root";
private static String password = "root";
private static String driver = "com.mysql.cj.jdbc.Driver";
private static String url = "jdbc:mysql://localhost:3306/test_account?serverTimezone=GMT&characterEncoding=utf-8";
static {
//注册驱动
try {
Class.forName(driver);
connection= DriverManager.getConnection(url,username,password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
/**
* 获取实例的方法
*/
public static Connection getConnection(){
return connection;
}
}
事务管理工具类:
AffairsUtils:
/**
* @author shizi 2022/2/2
* 事务管理工具类
*/
public class AffairsUtils {
private AffairsUtils(){}
/**
* 开启事务
*/
public static void beginAffairs(){
try {
JDBCUtils.getConnection().setAutoCommit(false);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
/**
* 提交事务
*/
public static void commitAffairs(){
try {
JDBCUtils.getConnection().commit();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
/**
* 回滚事务
*/
public static void rollbackAffairs(){
try {
JDBCUtils.getConnection().rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
/**
* 关闭事务
*/
public static void closeAffairs(){
try {
JDBCUtils.getConnection().close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}