当前位置: 首页 > news >正文

去年做的电子请帖怎么找原网站站长统计工具

去年做的电子请帖怎么找原网站,站长统计工具,网站web,网站首页的尺寸写在前面:2020年面试必备的Java后端进阶面试题总结了一份复习指南在Github上,内容详细,图文并茂,有需要学习的朋友可以Star一下!GitHub地址:https://github.com/abel-max/Java-Study-Note/tree/master背景首…

87cf714ac64c1a70950155dd1b916e0e.png

写在前面:2020年面试必备的Java后端进阶面试题总结了一份复习指南在Github上,内容详细,图文并茂,有需要学习的朋友可以Star一下!

GitHub地址:https://github.com/abel-max/Java-Study-Note/tree/master

背景

首先请思考一下以下代码执行的结果:

  • LogAop.java
//声明一个AOP拦截service包下的所有方法
@Aspect
public class LogAop {@Around("execution(* com.demo.service.*.*(..))")public Object log(ProceedingJoinPoint joinPoint) throws Throwable {try {MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();Method method = methodSignature.getMethod();Object ret = joinPoint.proceed();//执行完目标方法之后打印System.out.println("after execute method:"+method.getName());return ret;} catch (Throwable throwable) {throw throwable;}}
}
  • UserService.java
@Service
public class UserService{public User save(User user){//省略代码}public void sendEmail(User user){//省略代码}//注册public void register(User user){//保存用户this.save(user);//发送邮件给用户this.sendEmail(user);}
}
  • UserServiceTest.java
@SpringBootTest
public class UserServiceTest{@Autowiredprivate UserService userService;@Testpublic void save(){userService.save(new User());}@Testpublic void sendEmail(){userService.sendEmail(new User());}@Testpublic void register(){UserService.register(new User());}
}

在执行 save 方法后,控制台输出为:

after execute method:save

在执行 sendEmail 方法后,控制台输出为:

after execute method:sendEmail

请问在执行 register() 方法后会打印出什么内容?

反直觉

这个时候可能很多人都会和我之前想的一样,在 register 方法里调用了 save 和 sendEmail ,那 AOP 会处理 save 和 sendEmail ,输出:

after execute method:save
after execute method:sendEmail
after execute method:register

然而事实并不是这样的,而是输出:

after execute method:register

在这种认知的情况下,很可能就会写出有 bug 的代码,例如:

@Service
public class UserService{//用户下单一个商品public void order(User user,String orderId){Order order = findOrder(orderId);pay(user,order);}@Transactionalpublic void pay(User user,Order order){//扣款user.setMoney(user.getMoney()-order.getPrice());save(user);//...其它处理}
}

当用户下单时调用的 order 方法,在该方法里面调用了 @Transactional 注解修饰的 pay 方法,这个时候 pay 方法的事务管理已经不生效了,在发生异常时就会出现问题。

理解 AOP

我们知道 Spring AOP 默认是基于动态代理来实现的,那么先化繁为简,只要搞懂最基本的动态代理自然就明白之前的原因了,这里直接以 JDK 动态代理为例来演示一下上面的情况。

由于 JDK 动态代理一定需要接口类,所以首先声明一个 IUserService 接口

  • IUserService.java
public interface IUserService{User save(User user);void sendEmail(User user);User register(User user);
}

编写实现类

  • UserService.java
public class UserService implements IUserService{@Overridepublic User save(User user){//省略代码}@Overridepublic void sendEmail(User user){//省略代码}//注册@Overridepublic void register(User user){//保存用户this.save(user);//发送邮件给用户this.sendEmail(user);}
}

编写日志处理动态代理实现

  • ServiceLogProxy.java
public static class ServiceLogProxy {public static Object getProxy(Class<?> clazz, Object target) {return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{clazz}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object ret = method.invoke(target, args);System.out.println("after execute method:" + method.getName());return ret;}});}
}

运行代码

  • Main.java
public class Main{public static void main(String[] args) {//获取代理类IUserService userService = (IUserService) ServiceLogProxy.getProxy(IUserService.class, new UserService());userService.save(new User());userService.sendEmail(new User());userService.register(new User());}
}

结果如下:

after execute method:save
after execute method:sendEmail
after execute method:register

可以发现和之前 Spring AOP 的情况一样, register 方法中调用的 save 和 sendEmail 方法同样的没有被动态代理拦截到,这是为什么呢,接下来就看看下动态代理的底层实现。

动态代理原理

其实动态代理就是在运行期间动态的生成了一个 class 在 jvm 中,然后通过这个 class 的实例调用真正的实现类的方法,伪代码如下:

public class $Proxy0 implements IUserService{//这个类就是之前动态代理里的new InvocationHandler(){}对象private InvocationHandler h;//从接口中拿到的register Methodprivate Method registerMethod;@Overridepublic void register(User user){//执行前面ServiceLogProxy编写好的invoke方法,实现代理功能h.invoke(this,registerMethod,new Object[]{user})}
}

回到刚刚的 main 方法,那个 userService 变量的实例类型其实就是动态生成的类,可以把它的 class 打印出来看看:

IUserService userService = (IUserService) ServiceLogProxy.getProxy(IUserService.class, new UserService());
System.out.println(userService.getClass());

输出结果为:

xxx.xxx.$Proxy0

在了解这个原理之后,再接着解答之前的疑问,可以看到通过 代理类的实例 执行的方法才会进入到拦截处理中,而在 InvocationHandler#invoke() 方法中,是这样执行目标方法的:

//注意这个target是new UserService()实例对象
Object ret = method.invoke(target, args);
System.out.println("after execute method:" + method.getName());

在 register 方法中调用 this.save 和 this.sendEmail 方法时, this 是指向本身 new UserService() 实例,所以本质上就是:

User user = new User();
UserService userService = new UserService();
userService.save(user);
userService.sendEmail(user);

不是动态代理生成的类去执行目标方法,那必然不会进行动态代理的拦截处理中,明白这个之后原理之后,就可以改造下之前的方法,让方法内调用本类方法也能使动态代理生效,就是用动态代理生成的类去调用方法就好了,改造如下:

  • UserService.java
public class UserService implements IUserService{//注册@Overridepublic void register(User user){//获取到代理类IUserService self = (IUserService) ServiceLogProxy.getProxy(IUserService.class, this);//通过代理类保存用户self.save(user);//通过代理类发送邮件给用户self.sendEmail(user);}
}

运行 main 方法,结果如下:

after execute method:save
after execute method:sendEmail
after execute method:save
after execute method:sendEmail
after execute method:register

可以看到已经达到预期效果了。

Spring AOP 中方法调用本类方法的解决方案

同样的,只要使用代理类来执行目标方法就行,而不是用 this 引用,修改后如下:

@Service
public class UserService{//拿到代理类@Autowiredprivate UserService self;//注册public void register(User user){//通过代理类保存用户self.save(user);//通过代理类发送邮件给用户self.sendEmail(user);}
}

好了,问题到此就解决了,但是需要注意的是 Spring 官方是不提倡这样的做法的,官方提倡的是使用一个新的类来解决此类问题,例如创建一个 UserRegisterService 类:

@Service
public class UserRegisterService{@Autowiredprivate UserService userService;//注册public void register(User user){//通过代理类保存用户userService.save(user);//通过代理类发送邮件给用户userService.sendEmail(user);}
}
来源:https://www.tuicool.com/articles/FVZ7rqy
http://www.lbrq.cn/news/2594089.html

相关文章:

  • 山东省城乡住房建设厅网站百度一下你就知道 官网
  • 网站制作软件是什么服务营销理论
  • 苏州推广有限公司荥阳seo
  • 营销网站的概念搜索引擎营销成功案例
  • 学习做网站需要多久网站设计费用
  • 自己如何做网站优化东莞全网推广
  • 做社区网站软件开发培训机构
  • 在线聊天网站怎么做百度问答怎么赚钱
  • 怎样做咨询网站google官网注册账号入口
  • 手机医疗网站模板qq营销
  • 直播教育网站建设seo网站推广全程实例
  • 1t网站空间主机多少钱百度怎么打广告在首页
  • wordpress有广告插件下载武汉seo首页优化公司
  • 公关公司主要做什么seo综合查询怎么用
  • 聊城做网站价位seo服务优化
  • 深圳顶级做网站公司seo怎么搞
  • 做电脑网站手机能显示肇庆网站建设
  • wordpress带支付功能主题重庆seo扣费
  • 专利减缓在哪个网站上做什么叫软文
  • 网站建设 熊掌号seo优化推广业务员招聘
  • 帝国cms如何做电影网站今日头条热搜榜前十名
  • 专做商品折扣的网站系统推广公司
  • 虚拟主机网站建设过程可以营销的十大产品
  • 公司网站可以自己建立吗谷歌推广代理公司
  • 信誉好的o2o网站建设百度查重工具
  • 丹东网站建设公司信息发布平台推广有哪些
  • 新疆生产建设兵团科技局网站北京百度推广投诉电话
  • 烟台高端网站建设公司哪家好全球网络营销公司排行榜
  • 沁水做网站湘潭网站seo磐石网络
  • .net做网站之前设置武汉seo学徒
  • 深入剖析 RAG 检索系统中的召回方式:BM25、向量召回、混合策略全解析
  • ShowDoc与Docmost对比分析:开源文档管理工具的选择指南
  • ART数据库索引结构--ART,The adaptive radix tree论文细读
  • ubuntu22.04系统入门 linux入门(二) 简单命令 多实践以及相关文件管理命令
  • ubuntu 镜像克隆
  • 嵌入式教学的云端革命:高精度仿真如何重塑倒车雷达实验与工程教育——深圳航天科技创新研究院赋能新一代虚实融合实训平台