Proxy design pattern of static and dynamic proxy agents (super ..) Comments

Original link: http://www.cnblogs.com/fingerboy/p/5335328.html

  When learning the Spring framework, there is an important idea is AOP, aspect-oriented programming, using the idea of AOP combined with some API Spring separating core business and supplementary services can be achieved, which can be in the implementation of the core business, some of the secondary business add to the mix, and auxiliary services (such as logging, access control, etc.) are generally some public services, thus achieving a separation between the two, making the code more purely core business, but also assist the business to get multiplexing, this one note was written when learning the spring, using springAPI and implement a custom class example of AOP  , .AOP underlying dynamic is achieved by proxy, recently learned about the special proxy mode, reflection, (also a reflection based dynamic proxy mechanisms to achieve) and three-dimensional understanding of the agency a little bit, let's explain the agency by example.

Why Agent:

  Playing one of the most simple example, I now want to learn, then you have to take over his bag, took out the book, pen and paper ready, then start learning, and other finished school I had to pick up the book, the book back into the bag , the bags have to sort out, this is a complete learning process, but I'm lazy and do not want to move, just learning, you may have to let my mother helped me to take over the bag, open the book, I just learn it well, after completion, and then my mother helped me put all the books back. (I make what is this broken example ...), here, mother represents a proxy object , people have to learn that I, and I'm just learning, so only the highest efficiency, as for the other to the proxy object (the mother) did just fine, painting an ugly look of the figure shows:

  Then think of the time we came into contact with jdbc database operations, business layer for each method, you need to 1. Open the database connection, 2. perform the operation we want 3. Close the database connection. This makes the business layer code is pure enough, I function is to query the user data, open and close the database connection off my hair doing something I want to shop and go to this thing that's a problem existing in traditional development, through code now show you??:

/ ** 
 * Simple service layer interface, only a save method 
 * / 
interface UserService {
     public  void saveUser (); 
} 
///////////////////////// ///////////////////////////////
/ ** * business layer implementation classes implement the save method * / class UserServiceImpl the implements UserService { @override public void saveUser () { System.out.println ( ". 1: open database Connectivity" ); System.out.println ( "2: store user information" ); System.out.println ( ". 3: Close the connection " ); } }

我们可以看到其实这个方法的实现是有问题的,核心业务与辅助业务写在了一个方法中,不但业务冗余了不说,像开关数据库连接这样的公共操作也大量的重复,这时候就出现了代理模式的思想,我们可以使用代理模式的思想改写一下上面的代码:

package com.wang.proxy;
/**
 * 简单业务层接口,只有一个save方法
 */
interface UserService{
    public void saveUser();
}

/**
 * 代理类
 */
class UserServiceProxy implements UserService{

    private UserService userService;
    
    public UserServiceProxy(UserService userService) {
        super();
        this.userService = userService;
    }

    public void open(){
        System.out.println("1:打开数据库连接");
    }
    public void close(){
        System.out.println("3:关闭数据库连接");
    }
    @Override
    public void saveUser() {
        this.open();
        userService.saveUser();
        this.close();
    }
    
}

/**
 * 业务层实现类,实现save方法
 */
class UserServiceImpl implements UserService{

    @Override
    public void saveUser() {
        System.out.println("2:保存用户信息");
    }
    
}
/**
 * 测试类
 */
public class TestProxy {
    
    public static void main(String[] args) {
        UserService userService =new UserServiceProxy(new UserServiceImpl());
        userService.saveUser();
    }
}

  通过测试代码打印结果,和上面没有使用代理的代码是完全一样,但是通过修改可以清晰地看到,业务层代码变得很纯很纯的,只剩下最核心的保存用户信息的代码.通过代理模式,我们可以抽取出核心业务与辅助业务,但是问题随之而来了,我这里编写的UserServiceProxy是挺不错,可是它只能服务与UserService这个接口的对象啊,如果我有一千个业务,那岂不是要编写一千个代理类,毕竟一千个人心中就有一千个哈姆雷特啊,其实这种代理模式就是静态代理,它的缺点很明显,静态代理只能服务于一种类型的对象,不利于业务的扩展,那么我们就想了,能不能设计一个代理类可以服务于所有的业务对象呢?于是,这时候,动态代理就闪亮登场了.

  如果要实现动态代理,那么你要编写的那个代理类就需要实现一个InvocationHandle接口.这个接口所在位置是java.lang.reflect.InvocationHandler.看到reflect我们就能知道,动态代理肯定是通过反射来实现的了,这个接口中有一个方法:

    Object  invoke(Object proxy, Method method, Object[] args)    :在代理实例上处理方法调用并返回结果。

    invoke方法其实是反射里边的一个方法,在这个方法中有三个参数:

    Ojbect proxy:表示需要代理的对象

    Method method:表示要操作的方法

    Object[] args:method方法所需要传入的参数(可能没有为,null.也可能有多个)

  如果要想让代理设计真正可用,我们还必须有一个代理类对象产生,这有用到了另一个类:java.lang.reflect.Proxy.我的中文jdk文档对他的描述是:

 Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。 

  在这个类下面,我们找到了这样一个方法:

  public static Object newProxyInstance(ClassLoader loader,
                                       Class<?>[] interfaces,
                                       InvocationHandler h)
                                  throws IllegalArgumentException

  该方法返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序.方法中有三个参数:

   参数:

     loader - 定义代理类的类加载器

     interfaces - 代理类要实现的接口列表

     h - 指派方法调用的调用处理程序

   返回:

    一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口 

  ok,有了这些知识,我们就可以来编写一个万能的动态代理类了.

class ServiceProxy implements InvocationHandler {

    private Object target=null;//保存真实业务对象
    /**
     * 返回动态代理类的对象,这样用户才可以利用代理类对象去操作真实对象
     * @param obj  包含有真实业务实现的对象
     * @return   返回代理对象
     */
    public Object getProxy(Object obj) {
        this.target=obj;//保存真实业务对象
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
                .getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        Object result=method.invoke(target, args);//通过反射调用真实业务对象的业务方法,并且返回
        return result;
    }

}

现在来测试一下好不好使:

/**
 * 测试类
 */
public class TestProxy {

    public static void main(String[] args) {
            UserService service=(UserService) new ServiceProxy().getProxy(new UserServiceImpl());
            service.saveUser();
    }
}


//打印结果:
//        2.保存用户信息

  看!!!!完美,你说什么?为什么没有打开数据库连接,和关闭数据库连接呢?  简单,我们直接在ServiceProxy中加入两个方法,open()和close(),一个放到method.invoke()上面,一个放到下面,就可以了,注意,我们现在编写的是一个万能的动态代理类了,没有和任何的业务层接口关联,所以接下来你就可以为所欲为了.

  下面来总结一下:

  动态代理和静态代理相比较,最大的好处就是接口中声明的所有的方法都被转移到一个集中的方法中去处理,就是invocke()方法.这样在接口中声明的方法比较多的情况下我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。

      动态代理只能代理接口,代理类都需要实现InvocationHandler类,实现invoke方法。该invoke方法就是调用被代理接口的所有方法时需要调用的,该invoke方法的返回值是被代理接口的一个实现类。

  那么有没有可能我们可以不依赖接口呢?这时候就需要CGLIB实现动态代理了,这个jar包可以让我们摆脱接口的烦恼,感兴趣的自己去查一下吧,反正我也没用,不会...

转载于:https://www.cnblogs.com/fingerboy/p/5335328.html

Guess you like

Origin blog.csdn.net/weixin_30721899/article/details/94790531