代理模式

定义:

代理模式是指,为其他对象提供一种代理,以控制对这个对象的访问。(保护和增强目标对象)

分为动态代理和静态代理。

一、静态代理:显示声明被代理对象

package com.gupaoedu.vip.pattern.proxy;

/**
 * Created by Tom on 2019/3/10.
 */
public interface Person {

    void findLove();
}
package com.gupaoedu.vip.pattern.proxy.staticproxy;

import com.gupaoedu.vip.pattern.proxy.Person;

/**
 * Created by Tom on 2019/3/10.
 */
public class Son implements Person{

    public void findLove(){
        System.out.println("儿子要求:肤白貌美大长腿");
    }

    public void findJob(){

    }

    public void eat(){

    }

}
package com.gupaoedu.vip.pattern.proxy.staticproxy;

import com.gupaoedu.vip.pattern.proxy.Person;

/**
 * Created by Tom on 2019/3/10.
 */
public class Father implements Person {
    private Son person;

    public Father(Son person){
        this.person = person;
    }

    public void findLove(){
        System.out.println("父亲物色对象");
        this.person.findLove();
        System.out.println("双方父母同意,确立关系");
    }

    public void findJob(){

    }


}
package com.gupaoedu.vip.pattern.proxy.staticproxy;

/**
 * Created by Tom on 2019/3/10.
 */
public class FatherProxyTest {

    public static void main(String[] args) {

        Father father = new Father(new Son());
        father.findLove();

        //农村,媒婆
        //婚介所

        //大家每天都在用的一种静态代理的形式
        //对数据库进行分库分表
        //ThreadLocal
        //进行数据源动态切换
    }

}

 

二、动态代理(JDK,CGLib,Gupao)

package com.gupaoedu.vip.pattern.proxy.dynamicproxy.jdkproxy;

import com.gupaoedu.vip.pattern.proxy.Person;

/**
 * Created by Tom on 2019/3/10.
 */
public class Girl implements Person {
    public void findLove() {
        System.out.println("高富帅");
        System.out.println("身高180cm");
        System.out.println("有6块腹肌");
    }
}
package com.gupaoedu.vip.pattern.proxy.dynamicproxy.jdkproxy;


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

/**
 * Created by Tom on 2019/3/10.
 */
public class JDKMeipo implements InvocationHandler {

    private Object target;
    public Object getInstance(Object target) throws Exception{
        this.target = target;
        Class<?> clazz = target.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }

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

    private void before(){
        System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");
        System.out.println("开始物色");
    }

    private void after(){
        System.out.println("OK的话,准备办事");
    }
}

 

package com.gupaoedu.vip.pattern.proxy.dynamicproxy.jdkproxy;

import com.gupaoedu.vip.pattern.proxy.Person;
import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;
import java.lang.reflect.Method;

/**
 * Created by Tom on 2019/3/10.
 */
public class JDKProxyTest {

    public static void main(String[] args) {
        try {
            Object obj = new JDKMeipo().getInstance(new Girl());
            Method method = obj.getClass().getMethod("findLove",null);
            method.invoke(obj);
            //obj.findLove();

            //$Proxy0
//            byte [] bytes = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{Person.class});
//            FileOutputStream os = new FileOutputStream("E://$Proxy0.class");
//            os.write(bytes);
//            os.close();

        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

原理:通过字节码重组,生成了新的类,新的方法(由静转动,实现增强,不能修改本来的类,只能生成新的类)

JDK动态代理的实现原理:

1,拿到被代理类的引用,并且获取他的所有接口(反射获取)

2,JDK Proxy类重新生成一个新的类,实现了被代理类所有接口的方法

3,动态生成Java代码,把增强的代码放到新生成的代码中

4,编译

5,加载运行

 

附加:自己动手写JDK动态代理接口(略)

静态代理和动态代理的区别:

静态代理:对目标对象有一定的限制,不符合开闭原则

动态代理:对目标对象的类型没有限制,但是目标对象要实现一个接口(生成代理对象的时候要扫描对象接口的方法),否则无法调用

实战演习:

分别使用静态代理和动态代理实现数据源的动态修改

SpringAOP使用代理模式实现。(切面增强)

 

 

CGLib:

动态生成一个类去继承目标类,来实现动态代理。(目标类不需要实现接口,也没有什么其他的限制)

package com.gupaoedu.vip.pattern.proxy.dynamicproxy.cglibproxy;

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

import java.lang.reflect.Method;

/**
 * Created by Tom on 2019/3/11.
 */
public class CGlibMeipo implements MethodInterceptor {


    public Object getInstance(Class<?> clazz) throws Exception{
        //相当于Proxy,代理的工具类
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        Object obj = methodProxy.invokeSuper(o,objects);
        after();
        return obj;
    }

    private void before(){
        System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");
        System.out.println("开始物色");
    }

    private void after(){
        System.out.println("OK的话,准备办事");
    }
}
package com.gupaoedu.vip.pattern.proxy.dynamicproxy.cglibproxy;

/**
 * Created by Tom on 2019/3/11.
 */
public class Customer {

    public void findLove(){
        System.out.println("儿子要求:肤白貌美大长腿");
    }
}
package com.gupaoedu.vip.pattern.proxy.dynamicproxy.cglibproxy;

import net.sf.cglib.core.DebuggingClassWriter;

/**
 * Created by Tom on 2019/3/11.
 */
public class CglibTest {
    public static void main(String[] args) {

        try {


            //JDK是采用读取接口的信息
            //CGLib覆盖父类方法
            //目的:都是生成一个新的类,去实现增强代码逻辑的功能

            //JDK Proxy 对于用户而言,必须要有一个接口实现,目标类相对来说复杂
            //CGLib 可以代理任意一个普通的类,没有任何要求

            //CGLib 生成代理逻辑更复杂,效率,调用效率更高,生成一个包含了所有的逻辑的FastClass,不再需要反射调用
            //JDK Proxy生成代理的逻辑简单,执行效率相对要低,每次都要反射动态调用

            //CGLib 有个坑,CGLib不能代理final的方法

            System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"E://cglib_proxy_classes");

            Customer obj = (Customer) new CGlibMeipo().getInstance(Customer.class);
            System.out.println(obj);
            obj.findLove();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

底层原理:生成3个类:

其一,生成代理类的一个子类,重写了父类的方法,在父类的方法中,先调用了intercept()方法,又调用了父类的原方法

其二,略。。。(晦涩难懂)

其三,略。。。(晦涩难懂)

 

如果动态代理,需要代理多个方法,可以结合策略模式实现,以后再讲。。

 

CGLib和JDK Proxy的区别:

1,JDK动态代理是实现了被代理对象的接口,CGLib是继承了被代理对象

2,JDK和CGLib都是在运行时期生成字节码,JDK是直接写Class字节码,CGLib使用ASM框架写class字节码,CGlib实现代理更复杂,生成代理类比JDK效率低

3,JDK调用代理方法是通过反射机制调用,CGLIb是通过FastClass机制直接调用方法,CGlib执行效率更高

 

SpringAOP使用代理的原则:

1,当bean有实现接口时,Spring会使用JDK动态代理

2,当bean没有实现接口时,Spring选择CGlib

3,spring通过配置可以强制使用CGLib,只需要在spring的配置中添加如下配置:

<aop:aspectj-autoproxy proxy-target-class="true"/>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值