1. 程式人生 > >java中動態代理的實現

java中動態代理的實現

pan ack ger data- 動態代理 bind 使用 intercept framework

動態代理的實現

使用的模式:代理模式。
代理模式的作用是:為其他對象提供一種代理以控制對這個對象的訪問。類似租房的中介。

兩種動態代理:
(1)jdk動態代理,jdk動態代理是由Java內部的反射機制來實現的,目標類基於統一的接口(InvocationHandler)
(2)cglib動態代理,cglib動態代理底層則是借助asm來實現的,cglib這種第三方類庫實現的動態代理應用更加廣泛,且在效率上更有優勢。

主要應用的框架:
Spring中的AOP,Struts2中的攔截器

具體實現:


1、定義接口和實現類

接口

技術分享
1 package com.example.service;
2 
3 public interface UserService {
4     public String getName(int id);
5 
6     public Integer getAge(int id);
7 }
技術分享

實現類

技術分享
package com.example.service.impl;

import com.example.service.UserService;

public class UserServiceImpl implements UserService {

    public String getName(int id) {
        System.out.println("------getName------");
        return "cat";
    }

    public Integer getAge(int id) {
        System.out.println("------getAge------");
        return 10;
    }
}
技術分享

2、jdk動態代理實現

技術分享
package com.example.jdk;

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


public class MyInvocationHandler implements InvocationHandler {
    private Object target;

    /**
     * 綁定委托對象並返回一個代理類
     *
     * @param target
     * @return
     */
    public Object bind(Object target) {
        this.target = target;
        //取得代理對象
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);   //要綁定接口(這是一個缺陷,cglib彌補了這一缺陷)
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if ("getName".equals(method.getName())) {
            System.out.println("------before " + method.getName() + "------");
            Object result = method.invoke(target, args);
            System.out.println("------after " + method.getName() + "------");
            return result;
        } else {
            Object result = method.invoke(target, args);
            return result;
        }
    }
}
技術分享 技術分享
package com.example.jdk;

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

/**
 * 測試類
 */
public class RunJDK {

    public static void main(String[] args) {
        MyInvocationHandler proxy = new MyInvocationHandler();
        UserService userServiceProxy = (UserService) proxy.bind(new UserServiceImpl());
        System.out.println(userServiceProxy.getName(1));
        System.out.println(userServiceProxy.getAge(1));
    }
}
技術分享

運行結果:
------before getName------
------getName------
------after getName------
cat
------getAge------
10

3、cglib動態代理實現:

JDK的動態代理機制只能代理實現了接口的類,而不能實現接口的類就不能實現JDK的動態代理,cglib是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現增強,但因為采用的是繼承,所以不能對final修飾的類進行代理。

CGLIB的核心類:
net.sf.cglib.proxy.Enhancer – 主要的增強類
net.sf.cglib.proxy.MethodInterceptor – 主要的方法攔截類,它是Callback接口的子接口,需要用戶實現
net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method類的代理類,可以方便的實現對源對象方法的調用。

net.sf.cglib.proxy.MethodInterceptor接口是最通用的回調(callback)類型,它經常被基於代理的AOP用來實現攔截(intercept)方法的調用。這個接口只定義了一個方法
public Object intercept(Object object, java.lang.reflect.Method method,
Object[] args, MethodProxy proxy) throws Throwable;

第一個參數是代理對像,第二和第三個參數分別是攔截的方法和方法的參數。原來的方法可能通過使用java.lang.reflect.Method對象的一般反射調用,或者使用 net.sf.cglib.proxy.MethodProxy對象調用。net.sf.cglib.proxy.MethodProxy通常被首選使用,因為它更快。

技術分享
package com.example.cglib;

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

import java.lang.reflect.Method;

public class CGLIBProxy implements MethodInterceptor {
    private Object target;

    /**
     * 創建代理對象
     *
     * @param target
     * @return
     */
    public Object getInstance(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        // 回調方法
        enhancer.setCallback(this);
        // 創建代理對象
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("++++++before " + methodProxy.getSuperName() + "++++++");
        System.out.println(method.getName());
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("++++++after " + methodProxy.getSuperName() + "++++++");

        return result;
    }
}
技術分享 技術分享
package com.example.cglib;

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

/**
 * 測試CGLIB
 */
public class RunCGLIB {

    public static void main(String[] args) {
        CGLIBProxy cglibProxy = new CGLIBProxy();
        UserService userService = (UserService) cglibProxy.getInstance(new UserServiceImpl());
        userService.getName(1);
        userService.getAge(1);
    }
}
技術分享

運行結果:
++++++before CGLIBgetNamegetName0++++++
getName
------getName------
++++++after CGLIBgetNamegetName0++++++
++++++before CGLIBgetAgegetAge1++++++
getAge
------getAge------
++++++after CGLIBgetAgegetAge1++++++

java中動態代理的實現