(转)java动态代理与aop

转自: Java 动态代理与AOP - 如果的事 - 博客园动态代理与AOP 代理模式 代理模式给某一个目标对象(target)提供代理对象(proxy),并由代理对象控制对target对象的引用。 模式图: 代理模式中的角色有: 抽象对象角色(Abstrachttps://www.cnblogs.com/chenny7/p/11201010.html


【1】代理模式

/*** 抽象对象角色*/
abstract class AbstractObject {public abstract void operation();
}
/*** 目标对象*/
class TargetObject extends AbstractObject {public void operation() {System.out.println("Do Something!");}
}
/*** 代理对象*/
public class ProxyObject extends AbstractObject {TargetObject targetObject = new TargetObject();@Overridepublic void operation() {System.out.println("do sth before");targetObject.operation();System.out.println("do sth after");}public static void main(String[] args) {new ProxyObject().operation();}
}

代理模式中的角色有:

  • 抽象对象角色(AbstractObject):声明了目标对象和代理对象的共同接口,这样依赖在任何可以使用目标对象的地方都可以使用代理对象。
  • 目标对象角色(RealObject):定义了代理对象所代表的目标对象。   
  • 代理对象角色(ProxyObject):代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或者之后,执行某个操作,而不是单纯的将调用传递给目标对象。

【2】静态代理与动态代理

按照代理类的创建时期,可分为静态代理和动态代理:

  • 静态代理:由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。
  • 动态代理:在程序运行时运用反射机制动态创建而成。

【2.1】静态代理

/*** 会飞接口*/
interface Flyable {void fly(long ms);
}
/*** 会飞的鸟*/
class Bird implements Flyable {@Overridepublic void fly(long ms) {System.out.println("bird is flying.");try {Thread.sleep(ms);} catch (Exception e ) {System.out.println("bird睡眠异常");}}
}
/*** 会飞的风筝*/
class Kite implements Flyable {@Overridepublic void fly(long ms) {System.out.println("kite is flying.");try {Thread.sleep(ms);} catch (Exception e ) {System.out.println("kite 睡眠异常");}}
}
/*** 静态代理*/
public class StaticProxy implements Flyable {private Flyable flyable;public StaticProxy(Flyable flyable) {this.flyable = flyable;}@Overridepublic void fly(long ms) {System.out.println("before fly");flyable.fly(ms);System.out.println("after fly");}public static void main(String[] args) {new StaticProxy(new Kite()).fly(1000);new StaticProxy(new Bird()).fly(1000);}
}

静态代理缺点:

  • 若接口  Flyable 增加一个方法,则目标对象(接口实现类)与代理类全都需要增加方法实现,全都需要修改代码;

【2.2】动态代理

/*** 动态代理*/
public class DynamicProxy implements InvocationHandler {private Object targetObject;public Object newProxyInstance(Object targetObject) {this.targetObject = targetObject;return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("before invoke");proxy = method.invoke(targetObject, args);System.out.println("before after");return proxy;}public static void main(String[] args) {DynamicProxy dProxy = new DynamicProxy();//  会飞的鸟Flyable bird = (Flyable)dProxy.newProxyInstance(new Bird());bird.fly(1000);// 风筝Flyable kite = (Flyable)dProxy.newProxyInstance(new Kite());kite.fly(1000);}
}

显然, 动态代理对象不需要实现目标对象接口,但目标对象一定要实现接口,否则不能使用代理;


【3】cglib 代理

1)应用场景:

  • 有的时候,目标对象可能只是一个单独的对象,并没有实现任何的接口,这个时候,我们就可以使用目标对象子类的方式实现代理,这种代理方式就是:Cglib代理,也叫做子类代理,它是在内存中构件一个子类对象,从而实现对目标对象的功能拓展。

2)cglib 介绍

  • Cglib是强大的高性能的代码生成包,它可以在运行期间拓展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)。
  • Cglib包的底层是通过使用一个小而快的字节码处理框架ASM来转换字节码并生成新的类,不鼓励直接只使用ASM,因为它要求你必须对JVM内部结构,包括class文件的格式和指令集都很熟悉。
class Plane {public void fly(long ms) {System.out.println("plane is flying");try {Thread.sleep(ms);} catch(Exception e) {System.out.println("plane睡眠异常");}}
}
public class CglibProxy implements MethodInterceptor {private Object target;public CglibProxy(Object target) {this.target = target;}public Object getProxyInstance() {Enhancer enhancer = new Enhancer(); // 1 实例化工具类enhancer.setSuperclass(this.target.getClass()); // 设置父类对象enhancer.setCallback(this); // 设置回调函数return enhancer.create(); // 创建子类,也就是代理对象}// 拦截器方法@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("before invoke");Object returnValue = method.invoke(target, objects);System.out.println("after invoke");return returnValue;}public static void main(String[] args) {CglibProxy cglibProxy = new CglibProxy(new Plane());Plane plane = (Plane)cglibProxy.getProxyInstance();plane.fly(1000);}
}

maven pom.xml 

 <!-- https://mvnrepository.com/artifact/cglib/cglib --><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version></dependency>

【4】 spring aop

1)Spring在新版本中对AOP功能进行了增强,体现在这么几个方面:

  •     在XML配置文件中为AOP提供了aop命名空间
  •     增加了AspectJ切点表达式语言的支持
  •     可以无缝地集成AspectJ

2)如何使用 引介切面(Introduction Advisor)为一个现有对象添加任何接口的实现:

2.1)定义两个接口及其实现类,包括 服务员与售货员;

public class SpringAopDef {
}
interface Waiter { // 服务员接口void greetTo(String client);void serveTo(String client);
}
class NaiveWaiter implements Waiter { // 服务员实现类public void greetTo(String client) {System.out.println("NaiveWaiter greet to " + client);}public void serveTo(String client) {System.out.println("NaiveWaiter serve to " + client);}
}
interface Seller {// 售货员接口int sell(String goods, String client);
}
class SmartSeller implements Seller { // 售货员实现类public int sell(String goods, String client) {System.out.println("a smart seller sells " + goods + " to " + client);return 100;}
}

2.2)下一步,我们想让 服务员充当售货员角色,可以卖东西;

引入切面:

@Aspect
public class EnableSellerAspect {@DeclareParents(value="com.swjtu.mybatis.proxy.springaop.NaiveWaiter" // 切点-目标类, defaultImpl = SmartSeller.class)  // 增强类public Seller seller; // 增强类接口
}

maven pom 引入spring依赖

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.swjtu.mybatis</groupId><artifactId>MybatisHello2</artifactId><version>0.0.1-SNAPSHOT</version><properties><spring.version>5.2.0.RELEASE</spring.version></properties>
.................
<dependencies><dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.9.4</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version></dependency><!-- Spring Dependencies --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency></dependencies>

beans.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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.0.xsdhttp://www.springframework.org/schema/context/http://www.springframework.org/schema/context/spring-context.xsd"><aop:aspectj-autoproxy/><bean id="waiter" class="com.swjtu.mybatis.proxy.springaop.NaiveWaiter"/><bean class="com.swjtu.mybatis.proxy.springaop.EnableSellerAspect"/><!-- 定义切面 --><bean id="testBeforeAdvice" class="com.swjtu.mybatis.proxy.springaop.advice.TestBeforeAdvice"/><aop:config proxy-target-class="true"><aop:advisor advice-ref="testBeforeAdvice" pointcut="execution(* com..*.Waiter.greetTo(..))"/></aop:config></beans>

切面如下:

public class TestBeforeAdvice implements MethodBeforeAdvice {@Overridepublic void before(Method method, Object[] objects, Object o) throws Throwable {System.out.println("before invoke");System.out.println("do busi");System.out.println("after invoke");}
}

当调用 Waiter.greetTo() 方法会调用 before 通知;

springaop 测试用例入口:

public class SpringAopMain {public static void main(String[] args) {// 获取上下文环境ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");Waiter waiter = (Waiter)context.getBean("waiter"); // 从上下文中获取bean// 调用服务员原有方法waiter.greetTo("zhangsan");waiter.serveTo("zhangsan");// 通过切面已经将 Waiter 实现了 Seller 接口,所以可以强制转换Seller seller = (Seller) waiter;seller.sell("apple", "zhangsan");}
}
// spring aop 打印日志 
before invoke
do busi
after invoke
NaiveWaiter greet to zhangsan
NaiveWaiter serve to zhangsan
a smart seller sells apple to zhangsan

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/329972.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ConcurrentHashMap的红黑树实现分析

转载自 ConcurrentHashMap的红黑树实现分析红黑树 红黑树是一种特殊的二叉树&#xff0c;主要用它存储有序的数据&#xff0c;提供高效的数据检索&#xff0c;时间复杂度为O(lgn)&#xff0c;每个节点都有一个标识位表示颜色&#xff0c;红色或黑色&#xff0c;有如下5种特性&a…

leetcode初级算法3.存在重复元素

leetcode初级算法3.存在重复元素 仅为个人刷题记录&#xff0c;不提供解题思路 题解与收获 我的解法&#xff1a; Arrays.sort(nums);for(int i 0; i < nums.length-1; i){if(nums[i] nums[i1]){return true;}}return false;官方题解&#xff1a; public boolean con…

sql server累计求和函数_SQL基础--SQL高级功能

一.窗口函数有什么用&#xff1f;在日常工作中&#xff0c;经常会遇到需要在每组内排名&#xff0c;比如下面的业务需求&#xff1a;排名问题&#xff1a;每个部门按业绩来排名topN问题&#xff1a;找出每个部门排名前N的员工进行奖励面对这类需求&#xff0c;就需要使用sql的高…

(转)【SpringMvc】如何使用form发送PUT和DELETE请求

转自&#xff1a; https://blog.csdn.net/cockroach02/article/details/82194126https://blog.csdn.net/cockroach02/article/details/82194126 一、当前现状 浏览器使用form提交信息的时候只支持GET和POST&#xff0c;如果需要在浏览器上使用PUT和DELETE请求方式的话&#…

leetcode初级算法4.只出现一次的数字

leetcode初级算法4.只出现一次的数字 仅为个人刷题记录&#xff0c;不提供解题思路 题解与收获 我的解法&#xff1a; public static int singleNumber(int[] nums) {if(nums.length 1){return nums[0];}Arrays.sort(nums);int slow 0;int fast 1;while(fast < nums.…

集合总结(Collection)

转载自 集合总结(Collection) 最近项目上线完&#xff0c;闲来无事&#xff0c;整理了关于集合相关对比&#xff0c;具体详见以下几点&#xff1a;1.ArrayList和Vector区别&#xff1a;这两个类都实现了List接口(List接口继承了Collection接口)&#xff0c;他们都是有序集合&am…

springboot接收浏览器发送delete请求( method not allowed 405解决方法)

【README】 浏览器使用form提交信息的时候只支持GET和POST&#xff0c;如果需要在浏览器上使用PUT和DELETE请求方式的话&#xff0c;只能使用欺骗的方式了&#xff0c;SpringMvc提供了HiddenHttpMethodFilter类来提供支持&#xff1b; 【1】前端 1&#xff09;list.html <…

tensorflow图形检测_社交距离检测器——Tensorflow检测模型设计

在隔离期间&#xff0c;我花时间在github上探索Tensorflow的大量预训练模型。这样做时&#xff0c;我偶然发现了一个包含25 个带有性能和速度指标的预训练对象检测模型的存储库。拥有一些计算机视觉知识并给出了实际的背景知识&#xff0c;我认为使用其中之一来构建社交隔离应用…

leetcode初级算法4.两个数组的交集 II

leetcode初级算法4.两个数组的交集 II 仅为个人刷题记录&#xff0c;不提供解题思路 题解与收获 我的解法&#xff1a;&#xff08;总结在代码中&#xff09; public int[] intersect(int[] nums1, int[] nums2) {//为空则返回if(nums1 null || nums2 null){return null;…

Java NIO:Buffer、Channel 和 Selector

转载自 Java NIO&#xff1a;Buffer、Channel 和 Selector本文将介绍 Java NIO 中三大组件 Buffer、Channel、Selector 的使用。 本来要一起介绍非阻塞 IO 和 JDK7 的异步 IO 的&#xff0c;不过因为之前的文章真的太长了&#xff0c;有点影响读者阅读&#xff0c;所以这里将它…

(转)使用IDEA将普通MAVEN项目转为WEB项目

转自&#xff1a; 使用IDEA将普通MAVEN项目转为WEB项目_yun0000000的博客-CSDN博客使用IDEA将普通MAVEN项目转为WEB项目https://blog.csdn.net/yun0000000/article/details/70664944 1、file--project Structure--,然后点“”号&#xff0c;,若没有war包&#xff0c;可修改mav…

python创建文件对象_python基础教程:文件读写

在Linux系统中&#xff0c;一切都是文件。但我们通常说的文件是保存在磁盘上的图片、文档、数据、程序等等。而在程序的IO操作中&#xff0c;很多时候就是从磁盘读写文件。本节我们讲解Python中的文件对象如何操作文件。创建文件对象 通过Python内置函数open()可以很容易的创建…

(转)springboot:添加JSP支持

转自&#xff1a; 14.springboot:添加JSP支持 - 简书&#xff08;1&#xff09;创建Maven web project 使用Eclipse新建一个Maven Web Project &#xff0c;项目取名为&#xff1a;spring-boot-jsp &#xff08;2&#xff09;在pom.xm...https://www.jianshu.com/p/4216bbd1e0…

leetcode初级算法5.加一

leetcode初级算法5.加一 仅为个人刷题记录&#xff0c;不提供解题思路 题解与收获 我的解法&#xff1a;&#xff08;总结在代码中&#xff09; public int[] plusOne(int[] digits) {//获取digits长度int length digits.length;//判断条件int count 0;//全是9的情况for …

epoll 浅析以及 nio 中的 Selector

转载自 epoll 浅析以及 nio 中的 Selector首先介绍下epoll的基本原理&#xff0c;网上有很多版本&#xff0c;这里选择一个个人觉得相对清晰的讲解&#xff08;详情见reference&#xff09;&#xff1a;首先我们来定义流的概念&#xff0c;一个流可以是文件&#xff0c;socket&…

转-SpringBoot——使用外置的Tomcat服务器

转自&#xff1a; SpringBoot——使用外置的Tomcat服务器_架构师的小跟班的博客-CSDN博客_springboot使用外置tomcat1 前言2 修改步骤2.1 修改打包方式&#xff08;jar -> war&#xff09;2.2 排除 SprignBoot的Web模块中的Tomcat依赖2.2.1 将嵌入的Tomcat依赖方式改成 pro…

leetcode初级算法6.字符串转整数(atoi)

leetcode初级算法6.字符串转整数(atoi) 仅为个人刷题记录&#xff0c;不提供解题思路 题解与收获 我的解法&#xff1a; public int myAtoi(String s) {//避免魔法值先设spaceString space " ";//如果是空或者是一串空字符串就滚回去&#xff01;if(s null || …

inner join on 加条件和where加条件_SQL学习笔记 - GROUP BY / JOIN / UNION

最近在DataCamp上学习SQL&#xff08;基于PostgreSQL&#xff09;的课程&#xff0c;本文主要记录自己易记混的点&#xff0c;以便日后参考学习&#xff0c;不做原理讲解。GROUP BY&#xff08;分组&#xff09;一般和聚合函数一起使用&#xff0c;包括COUNT()&#xff0c;AVG(…

Selector 实现原理

转载自 Selector 实现原理概述 Selector是NIO中实现I/O多路复用的关键类。Selector实现了通过一个线程管理多个Channel&#xff0c;从而管理多个网络连接的目的。 Channel代表这一个网络连接通道&#xff0c;我们可以将Channel注册到Selector中以实现Selector对其的管理。一个C…

转: 深入浅出-网络七层模型

转自 深入浅出&#xff0d;网络七层模型 - sunsky303 - 博客园引言 今天回顾一下&#xff0d;&#xff0d;网络七层模型&&网络数据包 网络基本概念 OSI模型 OSI 模型(Open System Interconnection model)是一个由国际标准化组织&#https://www.cnblogs.com/sunsky3…