静态代理动态代理

Posted alimayun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了静态代理动态代理相关的知识,希望对你有一定的参考价值。

  代理模式最大的优势就是能够解耦,在spring中也是广泛使用。spring中一个重要的特性就是aop,aop是个啥东西呢?其实很简单,比如现在有个业务方法,那这个业务方法很重要,涉及到非常重要的业务数据,那对于广大企业应用来说,为了以后能够及时的定位问题,需要记录相关入参以及出参到日志表。

技术分享图片

但是对于企业应用来说,需要记录日志的地方应该是蛮多的,如果每个方法中都手动的去写这些记录日志的东西,就会特别的冗余,那使用代理模式就可以解决。

 

一、静态代理

  1、User接口

package com.ty.staticProxy;

/**
 * @author Taoyong
 * @date 2018年7月1日
 * 天下没有难敲的代码!
 */
public interface User {

    /*
     * 业务逻辑接口
     */
    public void work(String workName);
}

  

  2、UserImpl实现类

package com.ty.staticProxy;

/**
 * @author Taoyong
 * @date 2018年7月1日
 * 天下没有难敲的代码!
 */
public class UserImpl implements User {

    /*
     * 实际业务逻辑实现方法
     */
    @Override
    public void work(String workName) {
        System.out.println("我是做" + workName + "的");
    }

}

 

  3、代理类

package com.ty.staticProxy;

/**
 * @author Taoyong
 * @date 2018年7月1日
 * 天下没有难敲的代码!
 * 此类为代理类,并且实现业务逻辑类接口,接收一个实际业务处理对象
 */
public class ProxyUser implements User {

    private User user;
    
    public ProxyUser(User user) {
        this.user = user;
    }
    
    @Override
    public void work(String workName) {
        /*
         * 调用实际业务逻辑处理前可以定制化一些功能
         */
        System.out.println("工作前先放松放松=============");
        /*
         * 调用实际业务逻辑处理方法
         */
        user.work(workName);
        /*
         * 调用实际业务逻辑处理后也可以定制一些功能
         */
        System.out.println("工作后还是要放松放松=============");
    }

}

 

  4、StaticProxyDemo

package com.ty.staticProxy;

/**
 * @author Taoyong
 * @date 2018年7月1日
 * 天下没有难敲的代码!
 */
public class StaticProxyDemo {

    public static void main(String[] args) {
        User proxyUser = new ProxyUser(new UserImpl());
        proxyUser.work("java开发");
    }
}

运行结果:

工作前先放松放松=============
我是做java开发的
工作后还是要放松放松=============

 

二、动态代理

在java中,实现动态代理主要有两种方式,一种是jdk动态代理,一种是cglib

1、jdk动态代理

User以及UserImpl跟上面一致

a、UserDynamicProxy

package com.ty.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * @author Taoyong
 * @date 2018年7月2日
 * 天下没有难敲的代码!
 */
public class UserDynamicProxy implements InvocationHandler {

    private User user;
    
    public UserDynamicProxy(User user) {
        this.user = user;
    }

    /*
     * jdk动态代理基于接口,其中proxy好像没啥卵用、method代表当前被代理对象的实际调用方法、args则代表方法参数
     * 由invoke方法对被代理对象进行相关的增强
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("工作前放松放松========");
        method.invoke(user, args);
        System.out.println("工作后也要放松放松===========");
        return null;
    }

}

 

b、DynamicProxyDemo

package com.ty.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * @author Taoyong
 * @date 2018年7月2日
 * 天下没有难敲的代码!
 */
public class DynamicProxyDemo {

    public static void main(String[] args) {
        User user = new UserImpl();
        InvocationHandler h = new UserDynamicProxy(user);
        /*
         * 使用Proxy的静态方法是生成代理类的核心。
         * 一共有三个参数:
         * 1、第一个参数是被代理类的类加载器,通过此类加载器将代理类加载入jvm中;
         * 2、第二个参数则是被代理类所实现的所有接口,需要所有的接口的目的是创建新的代理类实现被代理类的所有接口,保证被代理类所有方法都能够
         * 被代理。其实代理的核心就是新创建一个类并实例化对象,去集成被代理对象所有功能的同时,再加入某些特性化的功能;
         * 3、第三个参数则是真正的扩展,使用动态代理的主要目的就是能够对原方法进行扩展,尤其是对于大部分方法都具有的重复方法(例如记录日志),
         * 可以理解为面向切面编程中的增强.
         */
        User proxy = (User) Proxy.newProxyInstance(User.class.getClassLoader(), user.getClass().getInterfaces(), h);
        /*
         * 在调用生成的代理类对象后,调用原方法后,该method对象以及参数等会被传入到InvocationHandler的invoke方法中,由InvocationHandler的
         * invoke方法对被代理类对象进行增强。
         */
        proxy.work("敲代码");
        proxy.eat("吃大餐");
        
    }
}

 

 2、cglib代理

jdk动态代理的缺点就是必须基于接口,没有接口就无法实现代理,而cglib则是使用继承的方式去生成代理类,使用范围更广

a、添加cglib.jar、asm.jar(注意jar包版本)

使用cglib前必须进行导包,并且版本如果过低会导致报错

技术分享图片

 

 

b、UserImpl(使不使用接口都可以)

package com.ty.dynamic.cglib;

/**
 * @author Taoyong
 * @date 2018年7月1日
 * 天下没有难敲的代码!
 */
public class UserImpl {
    
    /*
     * 实际业务逻辑实现方法
     */
    public void work(String workName) {
        System.out.println("我是做" + workName + "的");
    }

    
}

 

c、CglibDynamicProxy

package com.ty.dynamic.cglib;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * @author Taoyong
 * @date 2018年7月2日
 * 天下没有难敲的代码!
 */
public class CglibDynamicProxy implements MethodInterceptor {

    /*
     * 实际的增强
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("这是前处理==============");
        methodProxy.invokeSuper(obj, objects);        
        System.out.println("这是前处理==============");
        return null;
    }

}

 

d、CglibProxyDemo

package com.ty.dynamic.cglib;

import net.sf.cglib.proxy.Enhancer;

/**
 * @author Taoyong
 * @date 2018年7月2日
 * 天下没有难敲的代码!
 */
public class CglibProxyDemo {

    public static void main(String[] args) {
        /*
         * 创建字节码增强器
         */
        Enhancer enhancer = new Enhancer();
        /*
         * 被代理类设置为字节码增强器父类,cglib使用的是继承方式去创建代理类
         */
        enhancer.setSuperclass(UserImpl.class);
        /*
         * 设置字节码增强器回调方法
         */
        enhancer.setCallback(new CglibDynamicProxy());
        /*
         * 创建代理实例
         */
        UserImpl userImpl = (UserImpl) enhancer.create();
        userImpl.work("敲代码");
    }
}

 

 

以上是关于静态代理动态代理的主要内容,如果未能解决你的问题,请参考以下文章

代理模式(静态代理jdk动态代理CGLib动态代理)

静态代理与动态代理

Java动态代理与静态代理的定义与区别??

静态代理和动态代理

什么静态/动态代理,内容详解,只要看就会懂

Spring之静态/动态代理模式