代理模式简单实现

代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.
好处:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.

代理模型的三种方式
  1. 静态代理
  2. 动态代理  
   JDK动态代理
   CGLIB动态代理

一、静态代理

  在不修改目标对象方法的基础上,对目标对象方法进行扩展。

  

package com.lemon.service;

//Service接口
public interface UserService {

    void save();

    void delete();

    void update();

}

 

 

package com.lemon.service.impl;

import com.lemon.service.UserService;

//Service实现
public class UserServiceImpl implements UserService {
    @Override
    public void save() {
        System.out.println("新增用户");
    }

    @Override
    public void delete() {
        System.out.println("删除用户");
    }

    @Override
    public void update() {
        System.out.println("修改用户");
    }
}

 

package com.lemon.a_staticproxy;

import com.lemon.service.UserService;

/**
 * 静态代理类
 * 实现日志扩展功能
 *要求:
 *1)和目标(类)实现同样的接口
 *2)在静态代理类中传入目标对象实例,以便调用目标对象的方法
 *3)可以在静态代理类的方法中添加代理逻辑代码
 */
public class LogProxy implements UserService{

    //接收目标对象实例
    private UserService userService;

    //使用构造方法传入目标对象实例
    public LogProxy(UserService userService){
        this.userService = userService;
    }

    @Override
    public void save() {
        System.out.println("before=====save");
        //调用目标对象的方法
        userService.save();
        System.out.println("after=====save");
    }

    @Override
    public void delete() {
        System.out.println("before=====save");
        //调用目标对象的方法
        userService.delete();
        System.out.println("after=====save");
    }

    @Override
    public void update() {
        System.out.println("before=====save");
        //调用目标对象的方法
        userService.update();
        System.out.println("after=====save");
    }
}

 

package com.lemon.a_staticproxy;

import com.lemon.service.UserService;
import com.lemon.service.impl.UserServiceImpl;

//测试 
public class Test {
    public static void main(String[] args) {
        //使用静态代理模式
        //1.创建目标对象
        UserService userService = new UserServiceImpl();
        //2.创建静态代理类对象
        UserService proxy = new LogProxy(userService);
        //3.调用代理类的方法
        proxy.save();
        proxy.update();
        proxy.delete();
    }
}

静态代理的缺点:

 1)一个静态代理类只能代理一个目标类

    2)静态代理类的每个方法都需要编写重复的代理逻辑,代码比较冗余

二、JDK动态代理

  前提:目标对象有接口的情况

package com.lemon.b_jdk_dynamic_proxy;

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

/**
 * 用于生成JDK动态代理对象的工具类
 */
public class LogProxy {

    /**
     * 生成JDK动态代理对象的方法
     *
     * 返回值:生成的JDK动态代理对象
     * 参数:target, 传入目标对象
     */
    public static Object getProxy(Object target){
        /**
         * 参数一:类加载器,JDK动态代理的底层使用类加载器来生成的一个动态类的。通常传入当前类的类加载器即可!!!(LogProxy.class.getClassLoader())
         * 参数二:目标对象的接口列表(所有接口),通常使用目标对象获取接口列表(target.getClass().getInterfaces())
         * 参数三:接口。 该用于编写  代理类的代理逻辑代码。通常我们要提供InvocationHandler接口的实现类(匿名内部类的方式提供)
         */
        return Proxy.newProxyInstance(
                LogProxy.class.getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {

                    /**
                     * invoke方法:用于编写 代理类的代理逻辑代码。
                     *      invoke方法在什么时候会被调用?
                     *            该方法会在调用JDK代理对象的每个方法的时候被执行!!!!!
                     *
                     * @param proxy: 生成JDK动态代理对象
                     * @param method: 目标对象的执行方法的对象
                     * @param args: 目标对象的方法参数列表
                     * @return 返回值:目标对象方法执行后的返回结果
                     * @throws Throwable
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //获取目标对象的方法名称
                        String methodName = method.getName();

                        System.out.println("before======"+methodName);

                        //获取方法的参数列表
                       /* if(args!=null)
                        System.out.println(Arrays.asList(args));*/

                        //调用目标对象的方法
                        /**
                         * 参数一:执行的对象(必须传入目标对象,不能传入代理对象,否则会死循环)
                         * 参数二:方法的参数列表
                         */
                        Object result = method.invoke(target,args);

                        System.out.println("after======"+methodName);

                        return result;
                    }
                }
        );
    }
}

 

package com.lemon.b_jdk_dynamic_proxy;

import com.lemon.service.UserService;
import com.lemon.service.impl.UserServiceImpl;

/**
 * 演示JDK动态代理
 */
public class Demo {

    public static void main(String[] args) {
        //1.创建目标对象
        UserService userService = new UserServiceImpl();
        //2.创建静态代理类对象
        UserService proxy = (UserService) LogProxy.getProxy(userService);
        //3.调用代理类的方法
        proxy.save();
        proxy.delete();
        proxy.update();
    }
}

 

三、CGLIB动态代理

  目标对象可有可无

<!-- 导入spring-core(包含cglib依赖) -->
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
    </dependencies>

 

package com.lemon.c_cglib_dynamic_proxy;


import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * 用于生成Cglib代理对象的工具类
 */
public class LogProxy {


    /**
     * 生成Cglib代理对象
     * 返回值:生成的Cglib子类代理对象
     * 参数:目标对象(目标对象没有接口)
     */
    public static Object getProxy(Object target){

        /**
         * 方法返回值:生成的Cglib子类代理对象
         * 参数一:目标对象的类型(target.getClass()) (其实目标对象的类型就是Cglib代理对象 的  父类)
         * 参数二:MethodInterceptor接口,用于编写 代理对象的代理逻辑代码。通常提供MethodInterceptor接口的匿名内部即可
         */
        return Enhancer.create(
                target.getClass(),
                new MethodInterceptor() {
                    /**
                     * intercept方法:在调用代理对象的每个方法的时候会执行
                     * @param proxy: 生成的代理对象
                     * @param method: 目标对象的方法对象
                     * @param args: 目标对象的方法参数列表
                     * @param methodProxy: 代理对象的方法对象
                     * @return
                     * @throws Throwable
                     */
                    @Override
                    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

                        //获取目标对象的方法名称
                        String methodName = method.getName();

                        System.out.println("before======"+methodName);

                        /**
                         * 调用目标对象的方法
                         */
                        //方式一:直接使用目标对象 调用 目标对象的方法
                        Object result = method.invoke(target,args);
                        //方式二:使用代理类(子类)调用 目标对象(父类)的方法
                        //invokeSuper: 调用父类的方法
                        //Object result = methodProxy.invokeSuper(proxy,args);

                        System.out.println("after====="+methodName);

                        return result;
                    }
                }
        );
    }

}

 

package com.lemon.c_cglib_dynamic_proxy;

import com.lemon.b_jdk_dynamic_proxy.LogProxy;
import com.lemon.service.UserService;
import com.lemon.service.impl.UserServiceImpl;

/**
 * 演示JDK动态代理
 */
public class Demo2 {

    public static void main(String[] args) {
        //1.创建目标对象
        UserService userService = new UserServiceImpl();
        //2.创建静态代理类对象
        UserService proxy = (UserService) LogProxy.getProxy(userService);
        //3.调用代理类的方法
        proxy.save();
        proxy.delete();
        proxy.update();
    }
}

 

posted @ 2019-09-04 11:07  闲云陌路  阅读(927)  评论(0编辑  收藏  举报