之前说过了我对IOC的理解,这篇文章说以下我对动态代理和基本的对AOP的理解。

所谓动态代理就是,在运行时,动态创建实现了一组指定接口的实现类对象。

比如有:

interface A {
}
interface B{
}

即:

Object o = 方法(new Class[] {A.class,B.class}) ,

o实现了A和B两个接口

但是我们在运行时是无法写源代码来进行这个类的创建。

这时候我们需要用到Proxy类下的newProxyInstance()方法。

1.newProxyInstance()方法

Object proxyObject = Proxy.newProxyInstance(ClassLoader classLoader, Class[] interfaces, InvocationHandler h);

1. 方法作用:动态创建实现了interfaces数组中所有指定接口的实现类对象!

参数;

1. ClassLoader:类加载器!

* 它是用来加载器的,把.class文件加载到内存,形成Class对象!

2. Class[] interfaces:指定要实现的接口们

3. InvocationHandler:代理对象的所有方法(个别不执行,getClass())都会调用InvocationHandler的invoke()方法。

我们来看这个方法的使用方式:

public class Demo1 {
@Test
public void fun1() {
/* 1. ClassLoader
* 方法需要动态生成一个类,这个类实现了A、B接口,然后创建这个类的对象!
* 需要生成一个类,这个类也需要加载到方法区中,谁来加载,当然是ClassLoader!!!
* 2. Class[] interfaces
* 它是要实现的接口们
* 3. InvocationHandler
* 它是调用处理器
* 代理对象的实现的所有接口中的方法,内容都是调用InvocationHandler的invoke()方法。
*/
ClassLoader loader = this.getClass().getClassLoader();//把当前使用的这个类的类加载器给代理对象使用
InvocationHandler h = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("动态代理!");
return "xxx";
}
};
// 使用三大参数创建代理对象!!!
Object o = Proxy.newProxyInstance(loader, new Class[]{A.class, B.class}, h);
// 强转成A和B类型
A a = (A) o;
B b = (B) o; Object result = a.aaa("hello", 100);
System.out.println(result);
}
}

和两个接口:

interface A {
public void a();
public void aa();
public Object aaa(String s, int i);
} interface B {
public void b();
public void bb();
}

将o强转成A和B类型后,可以调用A接口中的方法和B接口中的方法,但是不论调用什么方法最中都是调用的InvocationHandler中的 invoke方法即打印输出动态代理!但是除此之外所有的Object中的非本地方法都是输出这个结果,这是因为Native方法不是用Java编写的所有就不需要管这个部分。

2.InvocationHandler接口其中只有invoke一种方法:

public Object invoke(Object proxy, Method method, Object[] args);

这个invoke()方法在调用代理对象所实现接口中的方法时被创建

* Object proxy:当前对象,即代理对象!在调用谁的方法!

* Method method:当前被调用的方法(目标方法)

* Object[] args:实参!

当在调用这个方法时,其对应关系为:

3.用动态代理进行增强

假设一个接口Waiter以及其一个实现类,该实现类提供一个方法:

public interface Waiter {
// 服务
public void serve();
}
public class ManWaiter implements Waiter {
public void serve() {
System.out.println("服务中...");
}
}

为了在调用ManWaiter的serve方法之外添加其他能力,就需要用动态代理来实现这样的功能:

public class Demo2 {
@Test
public void fun1() {
Waiter manWaiter = new ManWaiter();//目标对象
/*
* 给出三个参数,来创建方法,得到代理对象
*/
ClassLoader loader = this.getClass().getClassLoader();
Class[] interfaces = {Waiter.class};
InvocationHandler h = new WaiterInvocationHandler(manWaiter);//参数manWaiter表示目标对象
// 得到代理对象,代理对象就是在目标对象的基础上进行了增强的对象!
Waiter waiterProxy = (Waiter)Proxy.newProxyInstance(loader, interfaces, h); waiterProxy.serve();//前面添加“您好”, 后面添加“再见”
}
} class WaiterInvocationHandler implements InvocationHandler {
private Waiter waiter;//目标对象 public WaiterInvocationHandler(Waiter waiter) {
this.waiter = waiter;
}
} public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("您好!");
this.waiter.serve();//调用目标对象的目标方法
System.out.println("再见!");
return null;
}
}

我们在invoke 中实现了对对象能力的增强,这就是使用动态代理的能力。

4.在之前的基础上,为了提升动态代理的能力,实现了让目标对象和增强都是可以切换的,在创建目标对象之外,还需要查创建增强对象接口,

public interface BeforeAdvice {
public void before();
} public interface AfterAdvice {
public void after();
}

创建一个代理工厂,ProxyFactory:

/**
* 1. 创建代理工厂
* 2. 给工厂设置三样东西:
* * 目标对象:setTargetObject(xxx);
* * 前置增强:setBeforeAdvice(该接口的实现)
* * 后置增强:setAfterAdvice(该接口的实现)
* 3. 调用createProxy()得到代理对象
* * 执行代理对象方法时:
* > 执行BeforeAdvice的before()
* > 目标对象的目标方法
* > 执行AfterAdvice的after()
* @author cxf
*
*/
public class ProxyFactory {
private Object targetObject;//目标对象
private BeforeAdvice beforeAdvice;//前置增强
private AfterAdvice afterAdvice;//后置增强 /**
* 用来生成代理对象
* @return
*/
public Object createProxy() {
/*
* 1. 给出三大参数
*/
ClassLoader loader = this.getClass().getClassLoader();
Class[] interfaces = targetObject.getClass().getInterfaces();
InvocationHandler h = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
/*
* 在调用代理对象的方法时会执行这里的内容
*/
// 执行前置增强
if(beforeAdvice != null) {
beforeAdvice.before();
} Object result = method.invoke(targetObject, args);//执行目标对象的目标方法
// 执行后置增强
if(afterAdvice != null) {
afterAdvice.after();
} // 返回目标对象的返回值
return result;
}
};
/*
* 2. 得到代理对象
*/
Object proxyObject = Proxy.newProxyInstance(loader, interfaces, h);
return proxyObject;
}
}

当我们使用代理工厂的时候就可以这样做来实现对象的增强:

public void fun1() {
ProxyFactory factory = new ProxyFactory();//创建工厂
factory.setTargetObject(new ManWaiter());//设置目标对象
factory.setBeforeAdvice(new BeforeAdvice() {//设置前置增强
public void before() {
System.out.println("您好!");
}
}); factory.setAfterAdvice(new AfterAdvice() {//设置后置增强
public void after() {
System.out.println("再见!");
}
}); Waiter waiter = (Waiter)factory.createProxy();
waiter.shouQian();
}

动态代理类似于装饰者模式,但是比装饰者模式更加灵活,动态代理的作用就是最终实现AOP(面向切面编程)。面向切面编程中,切面是一种新的模块机制,用来描述分散在对象,类或者方法中的横切关注点,横切关注点是会影响到整个应用程序关注功能,于正常的业务是正交的,这些横切关注点可以是事务,日志和安全性等其他功能。

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

  1. 18.5.2动态代理和AOP

    ----此处是JDK动态代理----package d18_5_2; public interface IDog { void info(); void run(); } package d18_5_ ...

  2. 关于反射和动态代理和AOP

    package Exercise.reflect; /** * 反射把java中所有的东西都当做对象,甚至是类的本身也作为一种对象,并把它作为Class的对象的实例: * 反射是把类.类的属性.方法都 ...

  3. Spring中AOP的两种代理方式(Java动态代理和CGLIB代理)

    第一种代理即Java的动态代理方式上一篇已经分析,在这里不再介绍,现在我们先来了解下GCLIB代理是什么?它又是怎样实现的?和Java动态代理有什么区别? cglib(Code Generation ...

  4. Spring中AOP的两种代理方式(Java动态代理和CGLIB代理-转载

    内容是摘抄的,不知最初的原作者,见谅 Java 动态代理.具体有如下四步骤: 通过实现 InvocationHandler 接口创建自己的调用处理器: 通过为 Proxy 类指定 ClassLoade ...

  5. JAVA高级架构师基础功:Spring中AOP的两种代理方式:动态代理和CGLIB详解

    在spring框架中使用了两种代理方式: 1.JDK自带的动态代理. 2.Spring框架自己提供的CGLIB的方式. 这两种也是Spring框架核心AOP的基础. 在详细讲解上述提到的动态代理和CG ...

  6. AOP的底层实现-CGLIB动态代理和JDK动态代理

    AOP是目前Spring框架中的核心之一,在应用中具有非常重要的作用,也是Spring其他组件的基础.它是一种面向切面编程的思想.关于AOP的基础知识,相信多数童鞋都已经了如指掌,我们就略过这部分,来 ...

  7. JDK动态代理和CGLIB的区别

    Aspect默认情况下不用实现接口,但对于目标对象,在默认情况下必须实现接口 如果没有实现接口必须引入CGLIB库 我们可以通过Advice中添加一个JoinPoint参数,这个值会由spring自动 ...

  8. SpringAOP-JDK 动态代理和 CGLIB 代理

    在 Spring 中 AOP 代理使用 JDK 动态代理和 CGLIB 代理来实现,默认如果目标对象是接口,则使用 JDK 动态代理,否则使用 CGLIB 来生成代理类. 1.JDK 动态代理 那么接 ...

  9. 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别。

    基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别. 我还是喜欢基于Schema风格的Spring事务管理,但也有很多人在用基于@Tras ...

随机推荐

  1. Day4上午

    expect100+50+50, In fact 100+10+0. 代码能力还有待提高,部分分应该能拿的.结果...力不从心啊. T1 贪心做的不知对不对. 看来思路是对的,不知道能不能对. 暴力做 ...

  2. vue将数据绑定到属性中

    *必须使用[] <tr v-for="(p,index) in prodects"> @*v-bind:class="styleType(index)&quo ...

  3. 2019.3.26判断是否回文(java实现)

    我所有的文章都是对我总结学习的总结,那里不好或者冒犯了那里,我先对您说声对不起,请告知我进行改正. 今天java老师作业题目是判断是一个字符串否是回文: emmmm,我的思路是将字符串逆序,然后使用方 ...

  4. 写英文bug的经验总结

    本文链接: https://www.cnblogs.com/hchengmx/p/10800855.html 由于工作原因,开bug的时候需要由英文开,刚开的时候比较痛苦,因为有些词汇老师用的不太准确 ...

  5. SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1fa5519] was not registered for synchronization because synchronization is not active

    Creating a new SqlSessionSqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1fa5519] w ...

  6. Html编码(&#数字型)与解码小结 - 针对Puny Code(中文域名)的解码处理

    学习并了解到Html编码的知识,源于工作中的产品需求.如果一个URL里面包含Puny Code(不仅仅指中文,还可能是韩文等Unicode里非英文的国家文字,本文以含中文的URL为例),而且这个URL ...

  7. Java—包装类、Date和SimpleDateFormat、Calendar类

    包装类 基本数据类型不能调用方法,功能简单,为了让基本数据类型也具备对象的特性,Java为每个基本数据类型提供了一个包装类,这样就可以像操作对象那样来操作基本数据类型. 基本类型和包装类之间的对应关系 ...

  8. Build 2017 | 今儿来说说火得不行的认知服务吧(内附微软开发者大会在线峰会报名地址)

    Everybody,新一期的 Build 2017 大会新技术详谈又来了,今天小编给大家带来了一个既智能又有趣的技术,你一定喜欢!不卖关子了,直奔我们本期的主题: [只需几行代码,就能让任何应用更智能 ...

  9. html:<link> 标签中的 media 属性

    HTML <link> 标签的 media 属性 定义和用法 media 属性规定被链接文档将显示在什么设备上. media 属性用于为不同的媒介类型规定不同的样式. media属性值 ( ...

  10. http 状态码集合

    HTTP常见状态码 200 301 302 404 500   HTTP状态码(HTTP Status Code) 状态码并不是每个都有,为了后期扩展.[update20170505] 一些常见的状态 ...