java架构解密——AOP之动态代理实现

在上篇博客中,我们在宏观上介绍了AOP的底层实现,具体见博客java架构解密——Spring框架的AOP,在博客中,我们讲述了Aop的一些设计上的思路,今天,咱们就具体的实现,和大家一起探讨,看看AOP是怎么一步一步走到今天,而且有些图,也要做些纠正!

一,代码演变

前提:最初要实现的功能(打招呼)

代码:

接口:

<span style="font-size:18px;">public interface Greeting {
	 void sayHello(String name);
}</span>

实现:

<span style="font-size:18px;">public class GreetingImpl  implements Greeting {

	@Override
    public void sayHello(String name) {  

        System.out.println("Hello! " + name);  

    }  

}</span>

1,要增加一个功能在打招呼前加入打印“befor”,在打招呼后打印“after”

修改后实现:

<span style="font-size:18px;">public class GreetingImpl  implements Greeting {

	@Override
    public void sayHello(String name) {
        before();
        System.out.println("Hello! " + name);
        after();
    }  

    private void before() {
        System.out.println("Before");
    }  

    private void after() {
        System.out.println("After");
    }  

}</span>

2,我想统一管理这些

如果有一天,图 1 中的深色代码段需要修改,那是不是要打开 3 个地方的代码进行修改?如果不是 3 个地方包含这段代码,而是 100 个地方,甚至是 1000 个地方包含这段代码段,那会是什么后果?

为了解决这个问题,我们通常会采用将如图 1 所示的深色代码部分定义成一个方法,然后在 3 个代码段中分别调用该方法即可。

代理的实现:

<span style="font-size:18px;">public class GreetingProxy implements Greeting {
	private GreetingImpl greetingImpl;  

    public GreetingProxy(GreetingImpl greetingImpl) {
        this.greetingImpl = greetingImpl;
    }  

    @Override
    public void sayHello(String name) {
        before();
        greetingImpl.sayHello(name);
        after();
    }  

    private void before() {
        System.out.println("Before");
    }  

    private void after() {
        System.out.println("After");
    }
}</span>

注意:这时候,GreetingImpl里没有befor和after方法!

3,动态更换代理

因为软件系统需求变更是很频繁的事情,系统前期设计方法 1、方法 2、方法 3 时只实现了核心业务功能,过了一段时间,我们需要为方法 1、方法 2、方法 3 都增加事务控制;又过了一段时间,客户提出方法 1、方法 2、方法 3 需要进行用户合法性验证,只有合法的用户才能执行这些方法;又过了一段时间,客户又提出方法 1、方法 2、方法 3 应该增加日志记录;又过了一段时间,客户又提出……面对这样的情况,我们怎么办?

类设计:

JDK代理实现:

<span style="font-size:18px;">public class JDKDynamicProxy
	implements InvocationHandler {  

	    private Object target;  

	    public JDKDynamicProxy(Object target) {
	        this.target = target;
	    }  

	    @SuppressWarnings("unchecked")
	    public <T> T getProxy() {
	        return (T) Proxy.newProxyInstance(
	            target.getClass().getClassLoader(),
	            target.getClass().getInterfaces(),
	            this
	        );
	    }  

	    @Override
	    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	        before();
	        Object result = method.invoke(target, args);
	        after();
	        return result;
	    }  

	    private void before() {
	        System.out.println("Before");
	    }  

	    private void after() {
	        System.out.println("After");
	    }
}</span>

客户端:

<span style="font-size:18px;">public class Client {
	public static void main(String[] args) {
        Greeting greeting = new JDKDynamicProxy(new GreetingImpl()).getProxy();
        greeting.sayHello("Jack");
    }
}</span>

运行时对象的关系:

4.1改进

缺点:必须有接口

CGLib代理:

CGLIB实现:

<span style="font-size:18px;">public class CGLibDynamicProxy implements MethodInterceptor {  

    private static CGLibDynamicProxy instance = new CGLibDynamicProxy();  

    private CGLibDynamicProxy() {
    }  

    public static CGLibDynamicProxy getInstance() {
        return instance;
    }  

    @SuppressWarnings("unchecked")
    public <T> T getProxy(Class<T> cls) {
        return (T) Enhancer.create(cls, this);
    }  

    @Override
    public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        before();
        Object result = proxy.invokeSuper(target, args);
        after();
        return result;
    }  

    private void before() {
        System.out.println("Before");
    }  

    private void after() {
        System.out.println("After");
    }  

}</span>

客户端:

<span style="font-size:18px;">public class Client {
	public static void main(String[] args) {
        Greeting greeting = CGLibDynamicProxy.getInstance().getProxy(GreetingImpl.class);
        greeting.sayHello("Jack");
    }
}</span>

运行时对象的关系:

总结:

进行到这里,一般的博客也许就会结束了,因为核心内容已经结束了,但是,咱们的征途是星辰和大海,咱们的征途才刚开始,这个AOP还很草率,还没有实现动态的组装,而且咱们的aop切面(公共服务)和代理类写在了一起,等等这些问题,解决这些问题,需要我们站在整个设计思路上下功夫,核心原理懂了,剩下的抽象和封装的工作,是考验一个人另一个能力的时候了,咱们,下节继续!

时间: 2024-08-29 06:32:30

java架构解密——AOP之动态代理实现的相关文章

用spring aop实现动态代理的例子

下面由我来给大家展示用spring aop实现动态代理的例子(电脑打印) 下面就看一下具体的代码: 先定义一个打印机的接口 1 package aop007_ComPrint; 2 3 public interface Print { 4 5 public void ColorPrint(); //彩色打印 6 public void WhitePrint(); //黑白打印 7 } 然后定义两个实现类,分别实现彩色打印和黑白打印 1 package aop007_ComPrint; 2 3 p

Java的反射机制和动态代理

介绍Java注解的时候,多次提到了Java的反射API.与javax.lang.model不同的是,通过反射API可以获取程序在运行时刻的内部结构.反射API中提供的动态代理也是非常强大的功能,可以原生实现AOP中 的方法拦截功能.正如英文单词reflection的含义一样,使用反射API的时候就好像在看一个Java类在水中的倒影一样.知道了Java类的内部 结构之后,就可以与它进行交互,包括创建新的对象和调用对象中的方法等.这种交互方式与直接在源代码中使用的效果是相同的,但是又额外提供了运行时

java反射机制中的动态代理

java反射机制中的动态代理 动态代理模式及其使用 步骤1:定义一个接口 //接口 interface Subject{ void action(); } 步骤2:定义一个接口的实现类,也就是被代理类 //被代理类 class RealSubject implements Subject { @Override public void action() { System.out.println("我是被代理类,请执行我"); } } 步骤3:定义一个实现InvocationHandle

java架构解密——Spring框架的AOP

一直以来,我们应用了不少的AOP框架,但是对于AOP的底层实现却没有过多的深入,古话就是"知其然,不知其所以然",随着AOP学术讨论的骤然兴起,我也开拓了自己的眼界,深入了解了AOP这个五彩斑斓的世界! 先来看看大众的定义: 百度百科: 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函

java架构解密——双容器优化aop

上篇博客中,提出,优化是个无止境的过程,的确,随着需求的变化,软硬件基础的升级,我们越来越不考虑代码的容量,而是考虑代码的质量,但是随着研究的深入,到了某个阶段,我们也要考虑代码的容量问题,这时,容器的概念,脱颖而出,在上篇博客将服务类作为一个接口传入,实际在后台是一个map容器,我们不仅包含了map的全部实现,还实现了服务类的叠加,但是美中不足的是,我们的业务类,还是单个的对象,就如下图: 类图改造 这时,我们如果想为更多的业务提供服务,就必须编写更多的aop,这不符合我们的原则,基于这一点,

java架构解密——用接口改造AOP

优化是个无止境的工作,在AOP的路上,我们走得很远,但是还有很多的工作,我们没有做,比如,将aop的业务部分封装成容器,将aop的服务部分改造成面向接口的,这样就不受具体的形式上的限制了!这样AOP的优化,就又前进了一步,也是符合咱们的面向接口编程的思想,下面就和我一起研究下如何将接口的思想融入到aop的实现中. 回顾: 在上篇博客中,我们将aop的服务封装到了容器中: 这样的好处就是我们可以使用配置文件扩展服务类,服务类不再受限于具体的形式与方法,而我们封装的服务类和动态代理,构成了这样的一个

java架构解密——实时动态aop

在上篇博客中个,咱们一起组建了一个容器,里面封装了业务,这样,咱们就将业务和服务的组装放到了客户端,而客户端就相当于咱们的开发中使用到的配置文件,大家发现问题了吗?就是我不能动态改动了?业务容器在代理完成后,重新添加一个容器,这时候,是不被允许的,那这个容器就是个编译时起作用的容器,他就丧失了很多的灵活性! 那怎么办呢?实际就是调换一下调用顺序就好,大家看看结果: 1,类图对比 改造后类图 2,代码实现: 2.1代理类的变化: /** * 打招呼动态代理类,给业务类添加功能 * 前一版本为JDK

java字节码生成与动态代理的实现

一.代码生成的例子 java中的javac命令就是字节码生成的“老祖宗”,并且它也是用java写的.还有Web 中的jsp编译器,编译时植入的AOP框架,还有很常用的动态代理,甚至在反射时JVM也有可能在运行时生成字节码来提高速度. 如果使用过Spring来做Bean的管理 ,那么就使用过动态代理,因为如果 Bean是面向接口的编程,那么在Spring内部都是通过 动态代理的方法来对Bean进行增强的. 二.例子 package com.company; import java.lang.ref

AOP jdk动态代理

一: jdk动态代理是Spring AOP默认的代理方法.要求 被代理类要实现接口,只有接口里的方法才能被代理,主要步骤是先创建接口,接口里创建要被代理的方法,然后定义一个实现类实现该接口,接着将被代理对象注入到一个中间对象,中间对象实现InvocationHandler接口,实现该接口可以在 被代理对象调用它的方法前后插入一些代码.Proxy.newProxyInstance()能利用中间对象来生产代理对象. 二: (1)创建接口: package net.wang.aop; /** * 被代