代理

代理顾名思义:代为处理。不是对目标对象的直接操作,而是通过代理对目标对象进行包装,此时可以在目标对象的基础上添加额外的操作以满足业务需求。图示

分类:动态代理、静态代理。

代理三要素:共同接口、真实对象、代理对象

引入代理的原因:

在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用【解耦】。

静态代理

public interface Action {
public void doSomething();
} public class Proxyc implements Action{
Action realObject;
public Proxyc(Action action) {
realObject = action;
}
@Override
public void doSomething() {
System.out.println("被拦截前...");
realObject.doSomething();
System.out.println("被拦截后...");
} public static void main(String[] args) {
Proxyc proxy = new Proxyc(new RealObject());
proxy.doSomething();
}
}

优点:扩展原功能,不侵入代码

缺点:假如有10个不同的实际对象,对应10个不同的方法,该如何写呢?

1) 要么创建不同的代理类,代理后这样:

proxy.doSomething()
proxy2.doSomething2()
proxy3.doSomething3()
...

问题:创建多个功能类似的代理类,仅传入的真实对象不同

2) 要么创建一个代理,实现不同的接口:

proxy.doSomething()
proxy.doSomething2()
proxy.doSomething3()
...

问题:代理类不断膨胀

动态代理

代理由静态转为静态源于静态代理引入的额外工作。

动态代理就是我们上面提到的方案一,只不过这些proxy的创建都是自动的并且是在运行期生成的。

很多繁琐的编程可以用动态代理解决

实现方式

  • 反射(依赖接口)

    •   优点:最小化依赖关系;平滑jdk升级;代码简单
  • cglib等(依赖子类)
    •   优点:不限制实现接口;只操作关心的类;高性能

反射方式举例

public interface Action {
public void doSomething();
} public class RealObject implements Action{
@Override
public void doSomething() {
System.out.println("I'm RealObject~");
}
} public class DynamicProxyHandler implements InvocationHandler {
private Object realObject; public DynamicProxyHandler(Object realObject) {
this.realObject = realObject;
} @Override
public Object invoke(Object object, Method method, Object[] args) {
Object result = null;
try {
result = method.invoke(realObject, args);
} catch (InvocationTargetException|IllegalAccessException e) {
e.printStackTrace();
}
return result;
} public static void main(String[] args) {
RealObject realObject = new RealObject();
Action action = (Action) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Action.class},
new DynamicProxyHandler(realObject));
action.doSomething();
}
}

通过Proxy.newProxyInstance()生成代理对象,需要传入3个参数:classLoader + 代理接口 + InvocationHandler实例,

其中InvocationHandler接口,该接口定义了一个invoke方法,proxy最是最终生成的一个代理实例,一般不会用到,参数method是被代理目标实例的某个具体的方法,通过它可以发起目标实例方法的反射调用;参数args是通过被代理实例某一个方法的入参,在方法反射调用时候使用,通过代理将横切逻辑代码和业务类的代码编织到了一起。

动态代理的应用场景

日志

监控

鉴权

......

AOP

切面编程,是对OOP(面向对象编程)的一种补充,解决OOP其对对于跨越不同类、对象,纠缠逻辑变现的不足

AOP实例1

public interface Waiter {
public void service();
} public class ManWaiter implements Waiter{
@Override
public void service() {
System.out.println("service...");
}
}
public interface BeforeAdvice {
public void before();
} public interface AfterAdvice {
public void after();
}
@Getter
@Setter
public class ProxyFactory {
Object target;
BeforeAdvice beforeAdvice;
AfterAdvice afterAdvice; public Object createProxy() {
ClassLoader classLoader = this.getClass().getClassLoader();
Class[] interfaces = target.getClass().getInterfaces();
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (beforeAdvice != null) {
beforeAdvice.before();
}
Object result = method.invoke(target, args);
afterAdvice.after();
return result;
}
};
Object proxyObject = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
return proxyObject;
} public static void main(String[] args) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new ManWaiter());
proxyFactory.setBeforeAdvice(new BeforeAdvice() {
@Override
public void before() {
System.out.println("Before Service.");
}
});
proxyFactory.setAfterAdvice(new AfterAdvice() {
@Override
public void after() {
System.out.println("After Service.........");
}
});
Waiter waiter = (Waiter)proxyFactory.createProxy();
waiter.service();
}
}

AOP实例2

public interface UserService {
public void service();
} public class UserServiceImpl implements UserService{
@Override
public void service() {
System.out.println("In Service.......");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Service end.");
}
}
public class MethodPerformance {
private long start;
private long end;
String serviceMethod; public MethodPerformance(String serviceMethod) {
this.serviceMethod = serviceMethod;
start = System.currentTimeMillis();
} public void printPerformance() {
end = System.currentTimeMillis();
System.out.println(serviceMethod + " cost Time: " + (end - start));
}
} public class PerformanceMonitor {
public static ThreadLocal<MethodPerformance> performanceThreadLocal = new ThreadLocal<>(); public static void begin(String method) {
System.out.println("Start monitor>>");
MethodPerformance methodPerformance = new MethodPerformance(method);
performanceThreadLocal.set(methodPerformance);
} public static void end() {
System.out.println("End monitor.");
performanceThreadLocal.get().printPerformance();
}
}
public class PerformanceHandler implements InvocationHandler {
Object target; public PerformanceHandler(Object object) {
target = object;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) {
Object result = null;
try {
PerformanceMonitor.begin(target.getClass().getName() + ":" + method.getName());
result = method.invoke(target, args);
PerformanceMonitor.end();
} catch (IllegalAccessException| InvocationTargetException e) {
e.printStackTrace();
}
return result;
} public static void main(String[] args) {
UserService userService = new UserServiceImpl();
ClassLoader classLoader = userService.getClass().getClassLoader();
Class[] interfaces = userService.getClass().getInterfaces();
InvocationHandler invocationHandler = new PerformanceHandler(userService);
UserService obj = (UserService) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
obj.service();
}
}

动态代理实现AOP的更多相关文章

  1. 动态代理到基于动态代理的AOP

    动态代理,是java支持的一种程序设计方法. 动态代理实现中有两个重要的接口和类,分别是InvocationHandler(interface),Proxy(class). 要实现动态代理,必须要定义 ...

  2. 动态代理实现AOP【转】

    http://blog.csdn.net/beijiguangyong/article/details/8624016 根据前面介绍的Proxy和InvocationHandler,实在很难看出这种动 ...

  3. .Net 动态代理,AOP

    .Net 动态代理,AOP 直接上代码了. /***************************************** * author:jinshuai * * E-mail:redfox ...

  4. 动态代理的两种方式,以及区别(静态代理、JDK与CGLIB动态代理、AOP+IoC)

    Spring学习总结(二)——静态代理.JDK与CGLIB动态代理.AOP+IoC   目录 一.为什么需要代理模式 二.静态代理 三.动态代理,使用JDK内置的Proxy实现 四.动态代理,使用cg ...

  5. Java动态代理-->Spring AOP

    引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓“登高必自卑,涉远必自迩”.以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系列分别介绍这些Jav ...

  6. .Net 框架实现AOP(动态代理实现AOP,本文为翻译)

    在上一节,我们将静态实现AOP,但是对于一个大型项目,要想为每个类,每个方法都去实现AOP ,进行日志记录和权限验证似乎是不可能的. 即使可能对于成百上千个类维护,也是很难维护.所以今天的主题就是如标 ...

  7. Java使用动态代理实现AOP

    参考资料: http://www.importnew.com/15420.htmlhttp://www.cnblogs.com/techyc/p/3455950.html Spring是借助了动态代理 ...

  8. DispatchProxy实现动态代理及AOP

    DispatchProxy类是DotnetCore下的动态代理的类,源码地址:Github,官方文档:MSDN.主要是Activator以及AssemblyBuilder来实现的(请看源码分析),园子 ...

  9. Java 动态代理与AOP

    动态代理与AOP 代理模式 代理模式给某一个目标对象(target)提供代理对象(proxy),并由代理对象控制对target对象的引用. 模式图: 代理模式中的角色有: 抽象对象角色(Abstrac ...

  10. Java 动态代理及AOP实现机制

    AOP实现机制http://www.iteye.com/topic/1116696 AOP: (Aspect Oriented Programming) 面向切面编程AOP包括切面(aspect).通 ...

随机推荐

  1. BERT(Bidirectional Encoder Representations from Transformers)

    BERT的新语言表示模型,它代表Transformer的双向编码器表示.与最近的其他语言表示模型不同,BERT旨在通过联合调节所有层中的上下文来预先训练深度双向表示.因此,预训练的BERT表示可以通过 ...

  2. 软件光栅器实现(二、VS和PS的运作,法线贴图,切空间的计算)

    二.软件光栅器的VS和PS的输入.输出和运作,实现法线贴图效果的版本.转载请注明出处. 这里介绍的VS和PS是实现法线映射的版本,本文仅介绍实现思路,并给出代码供参考.切空间计算.光照模型等相关公式不 ...

  3. rails应用的部署

    简单部署 RAILS_ENV=production rake secret /etc/profile export SECRET_KEY_BASE=刚才生成的密钥 source /etc/profil ...

  4. Pi的计算

    百度百科           圆周率用希腊字母 π(读作pài)表示,是一个常数(约等于3.141592654),是代表圆周长和直径的比值.它是一个无理数,即无限不循环小数.在日常生活中,通常都用3. ...

  5. java持有对象-集合类

    面阿里的时候,面试就让我说一下集合 当时由于条件原因没听清面试官的问题,后来面试后,面试官让问他问题的时候,才说明白是什么 下面就接受一下我了解的集合类 集合类中大致可以分为两个体系 一.collec ...

  6. 28.实现 strStr() 函数

    28.实现 strStr() 函数 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始).如果不存在, ...

  7. 一把梭系列 之 颜值不够VsCode来凑

    如果您的孩子不适应编译型语言怎么办? 如果您的孩子贪玩不想花多时间在编程上怎么办? 如果您还没有孩子怎么办? 如果您夜晚兼职觉不够睡又怎么办? 不妨试试 “ 拍 簧 片 ”. 妈了巴子的有点麻烦,但别 ...

  8. spark-submit(spark版本2.4.2)

    spark-submit官方文档 :http://spark.apache.org/docs/latest/submitting-applications.html Launching Applica ...

  9. Python爬虫学习之正则表达式爬取个人博客

    实例需求:运用python语言爬取http://www.eastmountyxz.com/个人博客的基本信息,包括网页标题,网页所有图片的url,网页文章的url.标题以及摘要. 实例环境:pytho ...

  10. python 字典详细使用

    1. 字典 字典是无序.可变序列. 定义字典时,每个元素的键和值用冒号分隔,元素之间用逗号分隔,所有的元素放在一对大括号“{}”中. 字典中的键可以为任意不可变数据,比如整数.实数.复数.字符串.元组 ...