https://www.runoob.com/design-pattern/design-pattern-intro.html 所有设计模式
主要内容有单例模式和代理模式以及动态代理所涉及到的反射,泛型等。
1.单例模式
https://www.cnblogs.com/tangxiao1996/p/7899393.html
系统中一个类只产生一个实例:
可以节省创建对象所花费的时间,尤其对于重量级对象而言
new操作减少,对内存的使用频率也会降低,减轻GC的压力,缩短GC停顿时间
因此对于关键组件和被频繁使用的对象,使用单例模式可以有效改善系统性能
懒汉模式,它的特点是运行时获得对象的速度比较慢,但加载类的时候比较快。它在整个应用的生命周期只有一部分时间在占用资源。
饿汉模式,它的特点是加载类的时候比较慢,但运行时获得对象的速度比较快。它从加载到应用结束会一直占用资源。
从用户体验的角度来说,我们应该首选饿汉模式。我们愿意等待某个程序花较长的时间初始化,却不喜欢在程序运行时等待太久,给人一种反应迟钝的感觉,所以对于有重量级对象参与的单例模式,我们推荐使用饿汉模式。
而对于初始化较快的轻量级对象来说,选用哪种方法都可以。如果一个应用中使用了大量单例模式,我们就应该权衡两种方法了。轻量级对象的单例采用懒汉模式,减轻加载时的负担,缩短加载时间,提高加载效率;同时由于是轻量级对象,把这些对象的创建放在使用时进行,实际就是把创建单例对象所消耗的时间分摊到整个应用中去了,对于整个应用的运行效率没有太大影响。
每台计算机可以有若干个打印机,如果每一个进程或者线程都独立地使用打印机资源的话,那么我们打印出来的结果就有可能既包含这个打印任务的一部分,又包含另外一个打印任务的一部分。所以,大多数的操作系统最终为打印任务设计了一个单例模式的假脱机服务Printer Spooler,所有的打印任务都需要通过假脱机服务进行。
https://www.cnblogs.com/t0000/p/8250686.html
http://www.importnew.com/18872.html (更细节一些)
第一、控制资源的使用,通过线程同步来控制资源的并发访问;
第二、控制实例产生的数量,达到节约资源的目的。
第三、作为通信媒介使用,也就是数据共享,它可以在不建立直接关联的条件下,让多个不相关的两个线程或者进程之间实现通信。
- 线程安全
- 延迟加载(在时间轴上分散系统压力,在很多实际场景中,根本不会调用,这会造成浪费)
- 序列化与反序列化安全(这个有可能会破坏单例)
2.代理模式
https://blog.youkuaiyun.com/szzt_lingpeng/article/details/81748396 (很详细,asm,javassist,cglib都有)
https://blog.youkuaiyun.com/zhaosx1234567/article/details/79261087 (cglib,jdk,javassist的简单例子)
代理模式上,基本上有Subject角色,RealSubject角色,Proxy角色。其中:Subject角色负责定义RealSubject和Proxy角色应该实现的接口;RealSubject角色用来真正完成业务服务功能;Proxy角色负责将自身的Request请求,调用realsubject 对应的request功能来实现业务功能,自己不真正做业务。

将重量级组件在轻量级组件内声明,并在真正需要的时候才创建对象。例子如下:

handle:
反射方面的知识(https://www.cnblogs.com/tech-bird/p/3525336.html)
在java中任何东西都可以看作是对象。因此,我们可采用一种统一的语法,任何地方均可照搬不误。但要注意,尽管将一切都“看作”对象,但操纵的标识符实际是指向一个对象的“句柄”(Handle)。在其他Java参考书里,还可看到有的人将其称作一个“引用”,甚至一个“指针”。可将这一情形想象成用遥控板(句柄)操纵电视机(对象)。只要握住这个遥控板,就相当于掌握了与电视机连接的通道。但一旦需要“换频道”或者“关小声音”,我们实际操纵的是遥控板(句柄),再由遥控板自己操纵电视机(对象)。如果要在房间里四处走走,并想保持对电视机的控制,那么手上拿着的是遥控板,而非电视机。
此外,即使没有电视机,遥控板亦可独立存在。也就是说,只是由于拥有一个句柄,并不表示必须有一个对象同它连接。
动态代理:(最后是实现的代码,cglib,jdk,javassist两种方法)
延迟加载,减少重复编码,增强方法。(目前的理解ovo)
动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。是因为所有被代理执行的方法,都是通过在InvocationHandler中的invoke方法调用的,所以我们只要在invoke方法中统一处理,就可以对所有被代理的方法进行相同的操作了。
1.java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。JDK动态代理所用到的代理类在程序调用到代理类对象时才由JVM真正创建,JVM根据传进来的 业务实现类对象 以及 方法名 ,动态地创建了一个代理类的class文件并被字节码引擎执行,然后通过该代理类对象进行方法调用。
2.而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理。
区别:
1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换
JDK动态代理和CGLIB字节码生成的区别?
(1)JDK动态代理只能对实现了接口的类生成代理,而不能针对类
(2)CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
因为是继承,所以该类或方法最好不要声明成final
javassist有两种动态代理的生成方式:1.使用代理工厂创建(和cglib类似,实现一个handle);2.通过动态代码创建。
Javassit.CtClass是一个class文件的抽象表示
classpool对象是一个ctclass对象的容器。一个ctclass对象被构建后,它被记录在classpool中。这是因为当编译的原文件关联到ctclass表现的类, 编译器要访问ctclass对象。
javassist详解http://www.cnblogs.com/sunfie/p/5154246.html
this的用法:
方法引用this指向正在执行方法的类的实例。静态方法不能使用this关键字,因为静态方法不属于类的实例,所以this也就没有什么东西去指向。构造器的this指向同一个类中,不同参数列表的另外一个构造器。ps:在构造器中,如果要使用关键字this,那么,必须放在第一行,如果不这样,将导致一个编译错误。构造器是不能被继承的。
泛型:
java中泛型的引入主要是为了解决两个方面的问题:1.集合类型元素在运行期出现类型装换异常,增加编译时类型的检查,2. 解决的时重复代码的编写,能够复用算法。
https://www.cnblogs.com/lwbqqyumidi/p/3837629.html
动态代理的代码实例:
package yarnsls.javaFile.com;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
import com.sun.org.apache.bcel.internal.generic.NEW;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtNewConstructor;
import javassist.CtNewMethod;
import javassist.NotFoundException;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
import javassist.util.proxy.ProxyObject;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import sun.reflect.Reflection;
interface Hello {
String sayHello(String str);
public void request();
String sayError(String str);
}
interface Goodbye{
abstract String sayBye(String str);
}
// JDK原生动态代理实现
class HelloImp implements Hello {
static {
System.out.println("static code");
}
@Override
public String sayHello(String str) {
return "HelloImp: " + str;
}
public String sayError(String str) {
System.out.println("in the imp");
return "it's impossible-> " + str;
}
@Override
public void request() {
// TODO Auto-generated method stub
System.out.println("requesting");
}
}
class LogInvocationHandler implements InvocationHandler {
private Hello hello = null;
public LogInvocationHandler(/* Hello hello */) {
// this.hello = hello;
System.out.println("this is class: " + getClass());
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
if (this.hello == null) {
hello = new HelloImp();
}
System.out.println("if code----");
if ("sayHello".equals(method.getName())) {
System.out.println("You said: " + Arrays.toString(args));
}
if ("sayError".equals(method.getName())) {
System.err.println("You said:" + Arrays.toString(args));
}
Thread.sleep(1000);
System.out.println("method is starting");
Object result = method.invoke(hello, args);
System.out.println("result: "+result);
return result;
}
}
class CglibProxy implements MethodInterceptor{
private Object target;
@Override
public Object intercept(Object obj, Method method, Object[] arr, MethodProxy proxy) throws Throwable {
System.out.println("Cglib动态代理,监听开始!");
Object invoke = method.invoke(target, arr);//方法执行,参数:target 目标对象 arr参数数组
System.out.println("Cglib动态代理,监听结束!");
return invoke;
}
//定义获取代理对象方法
public Object getCglibProxy(Object objectTarget){
//为目标对象target赋值
this.target = objectTarget;
Enhancer enhancer = new Enhancer();
//设置父类,因为Cglib是针对指定的类生成一个子类,所以需要指定父类
enhancer.setSuperclass(objectTarget.getClass());
enhancer.setCallback(this);// 设置回调
Object result = enhancer.create();//创建并返回代理对象
return result;
}
}
//需要导入javassist包 ----格式工厂方法
class javassistProxy implements MethodHandler{
private Object target;
@Override
public Object invoke(Object arg0, Method method, Method arg2, Object[] arg3) throws Throwable {
// TODO Auto-generated method stub
this.target = new HelloImp();
Object result = method.invoke(target, arg3);
System.out.println(method.getName());
return result;
}
public static Hello createProxy() throws InstantiationException, IllegalAccessException{
// 创建代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
// 设置被代理类的类型
proxyFactory.setInterfaces(new Class[]{Hello.class});
// 创建代理类的class
Class proxyClass = proxyFactory.createClass();
// 创建对象
Hello javassistProxy = (Hello)proxyClass.newInstance();
((ProxyObject) javassistProxy).setHandler(new javassistProxy());
return javassistProxy;
}
}
public class testproxy {
public void DynGenerateClass() throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException{
// 创建类池,true 表示使用默认路径 getDefault方法只是为了方便编写
// ClassPool pool = ClassPool.getDefault();
ClassPool pool = new ClassPool(true);
// 定义类名
CtClass mCt = pool.makeClass(Hello.class.getName()+"Javaassist-BytecodeProxy");
// 需要实现的端口
mCt.addInterface(pool.get(Hello.class.getName()));
// 添加构造器
mCt.addConstructor(CtNewConstructor.defaultConstructor(mCt));
// 添加类的字段信息 动态的java代码
mCt.addField(CtField.make("public " + Hello.class.getName() + " real;",mCt));
String name = HelloImp.class.getName();
// 添加方法
mCt.addMethod(CtNewMethod.make("public void request() { if(real == null)real = new "+ name+" ();real.request();}", mCt));
// 生成动态类
Class pcClass =mCt.toClass();
Hello hello = (Hello)pcClass.newInstance();
hello.request();
}
ClassLoader gClassLoader(){
System.out.println(super.getClass().getName());
return super.getClass().getClassLoader();
}
public void function() {
Hello hello = null;
hello = (Hello) Proxy.newProxyInstance(gClassLoader(), // 1.
// 类加载器
new Class<?>[] { Hello.class }, // 2. 代理需要实现的接口,可以有多个
new LogInvocationHandler());// 3. 方法调用的实际处理者
// 等价于下面这个
/*
* InvocationHandler实现类,里面有一个object对象,指向真正的实现类
* InvocationHandler handler = new MyInvocationHandler();
* 代理类,是有Proxy生成的,根据这点代码,已知的是,它实现了被代理类的接口,而且它有个参数为InvocationHandler作为参数的构造函数
* Class<?> proxyClass =Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
* Foo f = (Foo)proxyClass.getConstructor(InvocationHandler.class).newInstance(handler);
*/
System.out.println("-----");
// 在调用hello方法的时候,hello才真正的被创建,static code也开始运行
System.out.println(hello.sayError("I love you!"));
System.out.println(getClass().getClassLoader());
}
// 2. 然后在需要使用Hello的时候,通过JDK动态代理获取Hello的代理对象。
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, NotFoundException, CannotCompileException {
testproxy t = new testproxy();
Constructor constructor = testproxy.class.getConstructor();
// System.exit(0);
t.function();
System.out.println("-----------");
t.DynGenerateClass();
CglibProxy cglib = new CglibProxy();//实例化CglibProxy对象
Hello user = (Hello) cglib.getCglibProxy(new HelloImp());//获取代理对象
System.out.println(user.sayHello("hello again"));
Hello next = javassistProxy.createProxy();
System.out.println(next.sayHello("final hello"));
}
}

本文深入探讨了设计模式中的单例模式和代理模式,包括懒汉模式与饿汉模式的对比,以及动态代理的实现方式。文章详细解释了单例模式在资源控制、实例数量控制和通信媒介中的应用,同时对代理模式的Subject、RealSubject和Proxy角色进行了阐述,配以代码实例说明。
4117

被折叠的 条评论
为什么被折叠?



