十堰网站seo技巧扬州哪里做网站好
news/
2025/9/24 8:00:30/
文章来源:
十堰网站seo技巧,扬州哪里做网站好,微分销系统软件,中国十大科技公司排名为什么要用AOP
①现有代码缺陷 针对带日志功能的实现类#xff0c;我们发现有如下缺陷#xff1a; 对核心业务功能有干扰#xff0c;导致程序员在开发核心业务功能时分散了精力 附加功能分散在各个业务功能方法中#xff0c;不利于统一维护 ②解决思路 解决这两个问题我们发现有如下缺陷 对核心业务功能有干扰导致程序员在开发核心业务功能时分散了精力 附加功能分散在各个业务功能方法中不利于统一维护 ②解决思路 解决这两个问题核心就是解耦。我们需要把附加功能从业务功能代码中抽取出来。 解决方案一–代理模式 静态代理
public class CalculatorStaticProxy implements Calculator {
// 将被代理的目标对象声明为成员变量
private Calculator target;
public CalculatorStaticProxy(Calculator target) {
this.target target;
}
Override
public int add(int i, int j) {
// 附加功能由代理类中的代理方法来实现
System.out.println([日志] add 方法开始了参数是 i , j);
// 通过目标对象来实现核心业务逻辑
int addResult target.add(i, j);
System.out.println([日志] add 方法结束了结果是 addResult);return addResult;
}
}缺点静态代理确实实现了解耦但是由于代码都写死了完全不具备任何的灵活性。 动态代理写一个工厂类实现附加功能
public class ProxyFactory {private Object target;public ProxyFactory(Object target) {this.target target;}public Object getProxy(){//jdk动态代理 通过反射实现动态代理/**其中有三个参数* 1、classLoader加载动态生成的代理类ProxyFactory的类加载器* 2、interfaces目标对象实现的所有接口的class对象所组成的数组* 3、invocationHandler设置代理对象实现目标对象方法的过程即代理类中如何重写接口*/ClassLoader classLoader target.getClass().getClassLoader();Class?[] interfaces target.getClass().getInterfaces();InvocationHandler invocationHandler new InvocationHandler() {Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {/*** proxy代理对象* method代理对象需要实现的方法即其中需要重写的方法* argsmethod所对应方法的参数*/Object result null;try {System.out.println([动态代理][日志] method.getName()参数 Arrays.toString(args));result method.invoke(target, args);System.out.println([动态代理][日志] method.getName()结果 result);} catch (Exception e) {e.printStackTrace();System.out.println([动态代理][日志] method.getName()异常e.getMessage());} finally {System.out.println([动态代理][日志] method.getName()方法执行完毕);}return result;}};return Proxy.newProxyInstance(classLoader, interfaces,invocationHandler);}
动态代理方法 1.jdk动态代理 2.cglib动态代理
动态代理是AOP的底层实现原理
AOP的基础
AOP概念及相关术语
概述 AOPAspect Oriented Programming是一种设计思想是软件设计领域中的面向切面编程它是面向对象编程的一种补充和完善它以通过预编译方式和运行期动态代理方式实现在不修改源代码的情况下给程序动态统一添加额外功能的一种技术。 相关术语 横切关注点 从每个方法中抽取出来的同一类非核心业务。在同一个项目中我们可以使用多个横切关注点对相关方 法进行多个不同方面的增强。 通知 每一个横切关注点上要做的事情都需要写一个方法来实现这样的方法就叫通知方法。 前置通知在被代理的目标方法前执行 返回通知在被代理的目标方法成功结束后执行寿终正寝 异常通知在被代理的目标方法异常结束后执行死于非命 后置通知在被代理的目标方法最终结束后执行盖棺定论 环绕通知使用try…catch…finally结构围绕整个被代理的目标方法包括上面四种通知对应的所 有位置 切面 封装通知方法的类 目标 被代理的目标对象。 代理 向目标对象应用通知之后创建的代理对象。 连接点 切入点 定位连接点的方式。 如果把连接点看作数据库中的记录那么切入点就是查询记录的 SQL 语句。 Spring 的 AOP 技术可以通过切入点定位到特定的连接点。 切点通过 org.springframework.aop.Pointcut 接口进行描述它使用类和方法作为连接点的查询条件。 作用 **简化代码**把方法中固定位置的重复的代码抽取出来让被抽取的方法更专注于自己的核心功能提高内聚性。 **代码增强**把特定的功能封装到切面类中看哪里有需要就往上套被套用了切面逻辑的方法就被切面给增强了。
基于注解的AOP 举个栗子 依赖
dependency
groupIdorg.springframework/groupId
artifactIdspring-aspects/artifactId
version5.3.1/version
/dependency目标资源 接口
public interface Calculator {
int add(int i, int j);
int sub(int i, int j);
int mul(int i, int j);
int div(int i, int j);
}实现类
Component
public class CalculatorPureImpl implements Calculator {
Override
public int add(int i, int j) {
int result i j;
System.out.println(方法内部 result result);
return result;
}
Override
public int sub(int i, int j) {
int result i - j;
System.out.println(方法内部 result result);
return result;
}
Override
public int mul(int i, int j) {
int result i * j;
System.out.println(方法内部 result result);
return result;
}
Override
public int div(int i, int j) {
int result i / j;
System.out.println(方法内部 result result);
return result;
}
}创建切面类并配置
// Aspect表示这个类是一个切面类
Aspect
// Component注解保证这个切面类能够放入IOC容器
Component
public class LogAspect {
//execution(public int com.atguigu.aop.annotation.CalculatorImpl.*(..))为切入点表达式
Before(execution(public int com.atguigu.aop.annotation.CalculatorImpl.*(..)))
public void beforeMethod(JoinPoint joinPoint){
String methodName joinPoint.getSignature().getName();
String args Arrays.toString(joinPoint.getArgs());
System.out.println(Logger--前置通知方法名methodName参
数args);
}
After(execution(* com.atguigu.aop.annotation.CalculatorImpl.*(..)))
public void afterMethod(JoinPoint joinPoint){
String methodName joinPoint.getSignature().getName();
System.out.println(Logger--后置通知方法名methodName);
}
AfterReturning(value execution(*
com.atguigu.aop.annotation.CalculatorImpl.*(..)), returning result)
public void afterReturningMethod(JoinPoint joinPoint, Object result){
String methodName joinPoint.getSignature().getName();
System.out.println(Logger--返回通知方法名methodName结
果result);
}
AfterThrowing(value execution(*
com.atguigu.aop.annotation.CalculatorImpl.*(..)), throwing ex)
public void afterThrowingMethod(JoinPoint joinPoint, Throwable ex){
String methodName joinPoint.getSignature().getName();
System.out.println(Logger--异常通知方法名methodName异常ex);
}
//环绕通知 相当于四种普通通知的组合
Around(execution(* com.atguigu.aop.annotation.CalculatorImpl.*(..)))
public Object aroundMethod(ProceedingJoinPoint joinPoint){
String methodName joinPoint.getSignature().getName();
String args Arrays.toString(joinPoint.getArgs());
Object result null;
try {
System.out.println(环绕通知--目标对象方法执行之前);
//目标对象连接点方法的执行
result joinPoint.proceed();
System.out.println(环绕通知--目标对象方法返回值之后);
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println(环绕通知--目标对象方法出现异常时);
} finally {
System.out.println(环绕通知--目标对象方法执行完毕);
}
return result;
}切入点表达式的具体格式 切面的优先级 通过Order注解的value属性设置
声明式事务
编程式事务概念 事务功能的相关操作全部通过自己编写代码来实现
try {
// 开启事务关闭事务的自动提交
conn.setAutoCommit(false);
// 核心操作
// 提交事务
conn.commit();
}catch(Exception e){
// 回滚事务
conn.rollBack();
}finally{
// 释放数据库连接
conn.close();
}编程式的实现方式存在缺陷 细节没有被屏蔽具体操作过程中所有细节都需要程序员自己来完成比较繁琐。 代码复用性不高如果没有有效抽取出来每次实现功能都需要自己编写代码代码就没有得到复 用。 声明式事务 既然事务控制的代码有规律可循代码的结构基本是确定的所以框架就可以将固定模式的代码抽取出来进行相关的封装。 封装起来后我们只需要在配置文件中进行简单的配置即可完成操作。 好处1提高开发效率 好处2消除了冗余的代码 好处3框架会综合考虑相关领域中在实际开发环境下有可能遇到的各种问题进行了健壮性、性能等各个方面的优化
基于注解的声明式事务
在spring配置中开启事务驱动
!--
开启事务的注解驱动
通过注解Transactional所标识的方法或标识的类中所有的方法都会被事务管理器管理事务
--
!-- transaction-manager属性的默认值是transactionManager如果事务管理器bean的id正好就
是这个默认值则可以省略这个属性 --
tx:annotation-driven transaction-managertransactionManager /添加事务注解 因为service层表示业务逻辑层一个方法表示一个完成的功能因此处理事务一般在service层处理 在Service对应的方法上添加注解Transactional Transactional注解标识的位置 Transactional标识在方法上咋只会影响该方法 Transactional标识的类上咋会影响类中所有的方法 事务属性回滚策略
声明式事务默认只针对运行时异常回滚编译时异常不回滚。 可以通过Transactional中相关属性设置回滚策略 rollbackFor属性需要设置一个Class类型的对象 rollbackForClassName属性需要设置一个字符串类型的全类名 noRollbackFor属性需要设置一个Class类型的对象 rollbackFor属性需要设置一个字符串类型的全类名 示例
Transactional(noRollbackFor ArithmeticException.class)
//Transactional(noRollbackForClassName java.lang.ArithmeticException)
public void buyBook(Integer bookId, Integer userId) {
//查询图书的价格
Integer price bookDao.getPriceByBookId(bookId);
//更新图书的库存
bookDao.updateStock(bookId);
//更新用户的余额
bookDao.updateBalance(userId, price);
System.out.println(1/0);
}事务属性事务隔离级别 隔离级别一共有四种 读未提交READ UNCOMMITTED 允许Transaction01读取Transaction02未提交的修改。 读已提交READ COMMITTED、 要求Transaction01只能读取Transaction02已提交的修改。 可重复读REPEATABLE READ 确保Transaction01可以多次从一个字段中读取到相同的值即Transaction01执行期间禁止其它事务对这个字段进行更新。 串行化SERIALIZABLE 确保Transaction01可以多次从一个表中读取到相同的行在Transaction01执行期间禁止其它事务对这个表进行添加、更新、删除操作。可以避免任何并发问题但性能十分低下。 事务属性事务传播行为 当事务方法被另一个事务方法调用时必须指定事务应该如何传播。例如方法可能继续在现有事务中运行也可能开启一个新事务并在自己的事务中运行。 示例 通过Transactional中的propagation属性设置事务传播行为 REQUIRED必需: 假设扣款和存款方法都标记为 REQUIRED。这意味着如果它们被一个非事务性的方法调用例如一个简单的按钮点击事件处理器它们会在新的事务中执行。但如果它们被一个已经在事务中运行的方法调用例如转账操作它们会加入这个已存在的事务。这就确保了转账操作中的扣款和存款要么都成功要么都不成功从而维护了数据的一致性。 REQUIRES_NEW需要新的: 现在假设我们将存款操作改为 REQUIRES_NEW。这意味着无论存款方法是如何被调用的它都会在一个新的事务中执行。这可能用于某些特殊场景比如即使扣款失败银行也希望确保某些类型的存款如利息支付总是执行。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/915270.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!