三种动态代理和三种工厂模式,单例模式

工厂模式:一种把创造(实例化)各种类类对象的工作抽出来的思想

简单的工厂模式:也叫静态的工厂模式,因为这个工厂类就办一件事创建实例化对象,方法可以定为static类型;
三种动态代理和三种工厂模式,单例模式_第1张图片
工厂方法模式:把实例化类的工作抽象成一个抽象方法,让实现这个抽象方法的类来完成实例化的工作,
三种动态代理和三种工厂模式,单例模式_第2张图片

抽象工厂模式:把实例化对象的工作抽象成一个接口,让实现这个接口的类去完成实例化工作:
三种动态代理和三种工厂模式,单例模式_第3张图片

代理:一句话说完,把调用某个类方法的工作(办理其实就是去调用某个类的方法)抽出来的思想

理一下:反射,动态代理,拦截器,AOP之间的关系:Proxy类通过反射生成接口或者类的代理类,调用InvokeHandle实现拦截(也就是拦截器),通过这个动态生成的代理类去调用代理对象就叫动态代理,利用动态代理来编写程序就叫aop
(至于动态代理类为什么会自动去执行InvokeHandle接口的Invoke()方法就要看Proxy.class源码和Method类的源码),把代理类的每一个方法(就是原来接口的方法)一个个的执行public Object invoke(Object proxy, Method method, Object[] args) 传来method方法对象,和这个方法所需要的所有参数args,再调用method的invoke()方法来执行方法。。。

package com.lqh.javastudy.dong_tai_dai_li;

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

/**
 * 2 * @Author: 刘钦华
 * 3 * @Date: 2019/10/15 9:16
 * 3 * @Dscription
 */
public class StuInvocationHandler implements InvocationHandler {
    //invocationHandler持有的被代理对象
    T target;

    public StuInvocationHandler(T target) {
        this.target = target;
    }

    /**
     * proxy:代表动态代理对象
     * method:代表正在执行的方法
     * args:代表调用目标方法时传入的实参
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理执行" +method.getName() + "方法");
        //代理过程中插入监测方法,计算该方法耗时
        Util.start();
        int n=1;
        Object result=null;
        if (n<0){
            result = method.invoke(target, args);
        }else {
            System.out.println("原来接口的方法没有执行");
        }
        
        Util.finish(method.getName());
        return result;
    }
}

之前“办理”都是在main函数里面调用某一个类的方法,然后就是把这调用的过程抽出来单独干了,就出现了的代理类,生成代理类是静态代理,动态代理,Cglib代理的关键:
java自带动态代理:

package com.lqh.javastudy.dong_tai_dai_li;

import org.apache.logging.log4j.message.MapMessage;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import com.alibaba.fastjson.JSON;
//import static org.apache.logging.log4j.message.MapMessage.MapFormat.JSON;

/**
 *
 * 动态代理的原理:
 * 加上反射机制生成一个实现代理接口的匿名类,
 * 利用拦截器(拦截器必须实现InvocationHanlder)通过这个调用
 * 
 *
 * 在调用具体方法前调用InvokeHandler来处理。
 * 动态代理:就是运行中新建一个代理类来执行它,(代理类和被代理类理解和静态代理的概念一样)
 *      生成动态代理类的工具就是Proxy类,这个类的产生就是整个动态代理的关键,由于是动态生成的类文件
 *      例如生成的代理类如public final class $Proxy0 extends Proxy implements Person
 *      这里的Person是一个接口,动态生成的代理类都是继承了Proxy类,又因为java只支持单继承,
 *      所以决定了Java动态代理只能继承接口来实现
 *      生成动态代理类后就需要一个对象实例来去代理,通过反射原理来创建一个代理对象
 *      这个动态生成的代理类持有一个中间类import java.lang.reflect.InvocationHandler;
 *      这个中间类InvocationHandler里面持有被代理对象 new StuInvocationHandler(zhangsan);
 *       通过聚合方式持有被代理对象的引用,把外部对invoke的调用最终都转为对被代理对象的调用。
 * 2 * @Author: 刘钦华
 * 3 * @Date: 2019/10/15 9:18
 * 3 * @Dscription
 */

/*jdk动态代理和Cglib如何选择:(这个目标对象就是上面的studeng,接口就是Person,在这里是student实现了Person接口的)
)如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP。

2)如果目标对象实现了接口,可以强制使用CGLIB实现AOP。

3)如果目标对象没有实现了接口,必须采用CGLIB库,Spring会自动在JDK动态代理和CGLIB之间转换。
* */
public class  main {
    public static void main(String[] args) throws InterruptedException {

        /*思路:在java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,
        通过这个类和这个接口可以生成JDK动态代理类和动态代理对象。
        * 我们执行这个ProxyTest类,先想一下,我们创建了一个需要被代理的学生张三,
        * 将zhangsan对象传给了stuHandler中,我们在创建代理对象stuProxy时,
        * 将stuHandler作为参数了的,上面也有说到所有执行代理对象的方法都会被替换成执行invoke方法,
        * 也就是说,最后执行的是StuInvocationHandler中的invoke方法。
        * */

        //创建一个实例对象,这个对象是被代理的对象
        Person zhangsan = new Student("张三");

         //创建一个与代理对象相关联的调用程序的接口InvocationHandler,
        // 这个接口只有一个方法,生成的代理类,调用原来被代理的接口的方法时都会去执行这个//方法(可以在原来方法上加上自己的东西)
        InvocationHandler stuHandler = new StuInvocationHandler(zhangsan);

        //创建一个代理对象stuProxy来代理 zhangsan,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
        Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class[]{Person.class}, stuHandler);
        System.out.println("代理对象"+ JSON.toJSON(stuProxy));
        //代理执行上交班费的方法
        stuProxy.giveMoney();
        stuProxy.sayhello();//每一个都会执行

        /*代理执行giveMoney方法
    张三上交班费
    giveMoney方法耗时1003ms
    代理执行sayhello方法
    hello
    sayhello方法耗时0ms
*/


        /*
        * 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。
        * 是因为所有被代理执行的方法,都是通过在InvocationHandler中的invoke方法调用的,
        * 所以我们只要在invoke方法中统一处理,就可以对所有被代理的方法进行相同的操作了。
        * 例如,这里的方法计时,所有的被代理对象执行的方法都会被计时,然而我只做了很少的代码量。*/
    }
}

Cglib代理:

package com.lqh.javastudy.Cglib;

import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;

/**
 * 2 * @Author: 刘钦华
 * 3 * @Date: 2019/11/6 20:25
 * 3 * @Dscription
 */
public class main {

    /*Cglib原来是一个项目,因为写的太好了就被广泛的应用到aop框架里面,例如spring aop
    它的原理:
    利用ASM框架,对代理对象类生成的class文件加载进来,通过修改其字节码生成子类来处理
    * 动态生成一个要代理的子类,子类重写要代理的类的所有不是final的方法。
    * 在子类中采用方法拦截技术拦截所有的父类方法的调用,顺势织入横切逻辑,
    * 它比Java反射的jdk动态代理要快
Cglib是一个强大的、高性能的代码生成包,它被广泛应用在许多AOP框架中,
为他们提供方法的拦截*/
    public static void main(String[] args) {
        /*jdk动态代理和Cglib如何选择:
        (这个目标对象就是上面的studeng,接口就是Person,在这里是helloService没有实现任何接口,就是没有继承接口)
)如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP。

2)如果目标对象实现了接口,可以强制使用CGLIB实现AOP。

3)如果目标对象没有实现了接口,必须采用CGLIB库,Spring会自动在JDK动态代理和CGLIB之间转换。
* */
        // 代理类class文件存入本地磁盘方便我们反编译查看源码
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\\java-study\\src\\main\\java\\com\\lqh\\javastudy\\Cglib");
        // 通过CGLIB动态代理获取代理对象的过程
        Enhancer enhancer = new Enhancer();
        // 设置enhancer对象的父类,这个父类就是被代理的对象
        enhancer.setSuperclass(HelloService.class);
        // 设置enhancer的回调对象
        enhancer.setCallback(new MyMethodInterceptor());
        // 创建代理对象
        HelloService proxy= (HelloService)enhancer.create();
        System.out.println("++++++++");
        System.out.println(proxy.toString());
        System.out.println("=======");
        // 通过代理对象调用目标方法
        proxy.sayHello();
        proxy.sayHello2();
    }


}

单例模式:想尽一切办法把一个类只能有一个实例对象的思想

首先,不是内部类不能加static的,只有内置类前面才能加static,所以,如果一个类的构造器不私有化,那么这个类都有可能被多次实例化,所以首先单例模式第一步就是把类的构造器私有化。
默写一下有几种单例模式的实现方法:
1.饿汉式(静态常量,final static)
2饿汉式(.静态代码块实例化)
3.懒汉式(线程不安全的,静态方法直接返回)
4.懒汉式(线程安全,在静态方法加synchrinized)
5.懒汉式(线程安全的,同步代码块)
6双重检查(加sychrnized,也加同步代码块)
7.静态内置类实现
不一一讲了。。。。

class类的详解

三种动态代理和三种工厂模式,单例模式_第4张图片

Method类的API

参考

 package com.lqh.javastudy.MethonClass;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 2 * @Author: 刘钦华
 * 3 * @Date: 2019/11/7 11:06
 * 3 * @Dscription
 */
public class main {
    public static void main(String[] strings) throws InvocationTargetException, IllegalAccessException {
        Person person=new Person();
        person.setName("小华");
        Class personClass = person.getClass();
        Method[] methods = personClass.getMethods();
        for (Method method:methods){
            System.out.println(method);
            System.out.println(method.getName());
            if (method.getName().equals("getName")){
                //代理的实质
                Object invokeResult = method.invoke(person, method.getParameters());
                System.out.println(invokeResult);
            }
        }
    }
}
``看输出
public java.lang.String com.lqh.javastudy.MethonClass.Person.getName()
getName
小华
public java.lang.Integer com.lqh.javastudy.MethonClass.Person.getId()
getId
public void com.lqh.javastudy.MethonClass.Person.setName(java.lang.String)
setName
public void com.lqh.javastudy.MethonClass.Person.setId(java.lang.Integer)
setId
public final void java.lang.Object.wait() throws java.lang.InterruptedException
wait
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
wait
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
wait
public boolean java.lang.Object.equals(java.lang.Object)
equals
public java.lang.String java.lang.Object.toString()
toString
public native int java.lang.Object.hashCode()
hashCode
public final native java.lang.Class java.lang.Object.getClass()
getClass
public final native void java.lang.Object.notify()
notify
public final native void java.lang.Object.notifyAll()
notifyAll

Process finished with exit code 0

你可能感兴趣的:(Java)