zoukankan      html  css  js  c++  java
  • Spring源码分析 之浅谈设计模式

    一直想专门写个Spring源码的博客,工作了,可以全身性的投入到互联网行业中。虽然加班很严重,但是依然很开心。趁着凌晨有时间,总结总结。

    首先spring,相信大家都很熟悉了。 

     1、轻量级  零配置,API使用简单

     2、面向Bean  只需要编写普通的Bean(一个Bean代表一个对象)

    3、松耦合 充分利用AOP思想 )(各自可以独立开发,然后整合起来运行)

    4、万能胶 与主流框架无缝集成 (Mybatis dubbo等等 )

    5、设计模式 将Java中经典的设计模式运用的淋漓尽致

    Spring解决企业级应用开发的负责设计,简化开发。

       1,基于POJO的清理爱你国际和最小侵入性(代码的嵌套,独自开发合起来运行)

      2,通过依赖注入和面向接口松耦合

      3、基于切面(典型的事务管理!!日志)和惯性进行声明式编程

      4、通过切面和模板减少版式代码

      主要通过,面向Bean、依赖注入以及面向切面三种方式达成

    Spring提供了IOC容器,通过配置文件或者注解的方式来管理对象之间的依赖关系

      A a = new A()//实例化后用一个变量保存下来(匿名对象)    ------------------》Spring用IOC容器 存储起来~

     a.c()  //必须初始化才运行  -----------------------> Spring帮忙初始化,实例化(控制器给了spring) 

    最终实现了 依赖注入:

    @autowrite Interfa A a   //自动吧他的实现类注入进来

    @Resource(“aa”)//IOC容器种类的id为“aa”的对象自动注入到这里

    @autowrite A a  //根据类型自动注入

    Spring的注入方式

    1、 setter

    2、 构造方法

    3、强制赋值

    面向切面,AOP核心思想--解耦! 把一个整体拆开,分别开发,发布时候,再组装到一起运行,切面就是规则!

    比如 事务;

         开启事务 执行事务 事务回滚 关闭事务     这就是规则!!!!!!

         这种有规律的,就可以认为他是固定的,可以单独拿出来开发设计,作为一个模块(比如日志啊)。

      AOP就是个编程思想而已

    关于Spring的使用,特点,网上资料很多,大家可以自己找找学习下。本博客主要对于源码进行解读。

    在典型的面型对象开发方式中,可能要将日志记录语句放在所有方法和Java类种才能实现日志功能。而在AOP方式中,可以反过来将日志服务模块化,并以声明的方式将他们应用到需要日志的组件上。Java类不需要知道日志服务的存在,也不想需要考虑相关的代码。

    AOP的功能完全集成到了Spring事务管理、日志和其他各种特性的上下文中

    authentication权限认证

    Logging日志

    Transctions Manager事务

    Lazy Loading懒加载

    Contex Process 上下文处理

    Error Handler 错误跟踪(异常捕获机制)

    Cache缓存

    1、除了AOP以外的设计模式

       a、 代理模式

       b、工厂模式

       c、单例模式

      d、委派模式

      e、策略模式

      f、策略模式

      g、原型模式

    代理模式原理:

       1、拿到被代理对象的引用,然后获取它的接口

       2、JDK代理重新生成一个类,同时实现我们给的代理对象所实现的接口

       3、把代理对象的引用拿到

       4、重新动态生成一个class字节码

       5、编译

    动态代理 调用哪个方法就代理哪个方法 

    整个类 生成一个新 的类

    大家认真仔细研究好代理模式,代理模式在Spring中 应用非常广泛!!!

    JDK代理模式实现:

      1、定义接口

      2、定义实现接口的类

      3、 代理类  ,代理类需要实现  InvocationHandler 接口,然后实现 invoke方法

     回顾一下,满足代理模式应用场景的三个必要条件,穷取法
    1、两个角色:执行者、被代理对象
    2、注重过程,必须要做,被代理对象没时间做或者不想做(怕羞羞),不专业
    3、执行者必须拿到被代理对象的个人资料(执行者持有被代理对象的引用)

     例:定义Persion接口

    复制代码
    public interface Person {
    
        //寻找真爱、相亲
        void findLove();
        
    //    String getSex();
    //
    //    String getName();
    
    }
    复制代码

    实现这个接口

    复制代码
    //小星星、单身
    public class XiaoXingxing implements Person{

    // private String sex = "女";
    // private String name = "小星星";

    @Override
    public void findLove() {
    // System.out.println("我叫" + this.name + ",性别:" + this.sex + "我找对象的要求是:");
    System.out.println("高富帅");
    System.out.println("有房有车的");
    System.out.println("身高要求180cm以上,体重70kg");
    }

    // public String getSex() {
    // return sex;
    // }
    //
    // public void setSex(String sex) {
    // this.sex = sex;
    // }
    //
    // public String getName() {
    // return name;
    // }
    //
    // public void setName(String name) {
    // this.name = name;
    // }


    }
    复制代码

    代理类

    复制代码
    //媒婆
    public class Meipo implements InvocationHandler {
    
        private Person target; //被代理对象的引用作为一个成员变量保存下来了   在下面调用时候的 的   ///////////////////////// 下面的嗲用
     
        //获取被代理人的个人资料为,为了能让他代理任何对象
        public Object getInstance(Person target) throws Exception {
            this.target = target;
            Class clazz = target.getClass();  //利用反射机制(最终获得接口)
            System.out.println("被代理对象的class是:" + clazz);
            return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);  //this这个参数 指的是 代理人 this.h   就是调用了媒婆的 invoke方法    this指的是invoke这个回调方法
        }
            //代理对象 会自动调用下面invoke方法
            @Override
            public Object invoke (Object proxy, Method  method, Object[] args) throws Throwable{
    
                System.out.println("我是媒婆:" + "得给你找个异性才行");
                System.out.println("开始进行海选...");
                System.out.println("------------");
      ///////////////////////////////////////////////////////////
                //调用的时候   (利用反射机制调用)   对象名.方法名 
                method.invoke(this.target, args);  这个invoke不是方法名字的invoke  是的话 会陷入死循环  
                System.out.println("------------");
                System.out.println("如果合适的话,就准备办事");
    
                return null;
            }
    
        }
    复制代码

    测试:

    复制代码
    public class TestFindLove {
        public static void main(String[] args) {
            
            try {
                
    //            
    //            Person obj = (Person)new Meipo().getInstance(new XiaoXingxing());
    //            System.out.println(obj.getClass());
    //            obj.findLove();
                
                //原理:
                //1.拿到被代理对象的引用,然后获取它的接口
                //2.JDK代理重新生成一个类,同时实现我们给的代理对象所实现的接口
                //3.把被代理对象的引用也拿到了
                //4.重新动态生成一个class字节码
                //5.然后编译
                
                //获取字节码内容 
    //            byte[] data = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});  //生成字节码文件
    //            FileOutputStream os = new FileOutputStream("E:/GP_WORKSPACE/$Proxy0.class");  //将字节码输入到磁盘上
    //            os.write(data);
    //            os.close();
                
                //是什么?
                //为什么?
                //怎么做?
             //解释: 字节码 反编译后 可以查看
    Person obj = (Person)new GPMeipo().getInstance(new XiaoXingxing()); //返回一个代理对象 代理出来的这个对象可以强转这个接口类 System.out.println(obj.getClass()); //这个Object对象 并不是 lcy的引用了 完全是一个新的对象 obj.findLove(); //动态代理 需要调用哪个方法 就调用哪个方法 整个类都是新的类了 新的字节码 } catch (Exception e) { e.printStackTrace(); } } }
    复制代码

    也可以不用 JDK的任何东西 自己实现动态代理!!

    不用jdk的任何东西!

    首先规定有个InvocationHandler  有个 invoke方法

    import java.lang.reflect.Method;
    
    public interface GPInvocationHandler {
         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
    }

    实现个Proxy  里面有 InvocationHandler引用  有 newInstance的方法 classloader方法

    复制代码
    import java.io.File;
    import java.io.FileWriter;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Method;
    
    import javax.tools.JavaCompiler;
    import javax.tools.JavaCompiler.CompilationTask;
    import javax.tools.StandardJavaFileManager;
    import javax.tools.ToolProvider;
    
    
    //生成代理对象的代码
    public class GPPorxy {
        
        private static String ln = "
    ";
        
        public static Object newProxyInstance(GPClassLoader classLoader,Class<?>[] interfaces,GPInvocationHandler h){
            
            
            try{
                //1、生成源代码
                String proxySrc = generateSrc(interfaces[0]);
                
                
                //2、将生成的源代码输出到磁盘,保存为.java文件
                String filePath = GPPorxy.class.getResource("").getPath();
                File f = new File(filePath + "$Proxy0.java");
                FileWriter fw = new FileWriter(f);
                fw.write(proxySrc);
                fw.flush();
                fw.close();
            
                //3、编译源代码,并且生成.class文件   
                JavaCompiler  compiler = ToolProvider.getSystemJavaCompiler();
                StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
                Iterable iterable = manager.getJavaFileObjects(f);
                
                CompilationTask task = compiler.getTask(null, manager, null, null, null, iterable);
                task.call();
                manager.close();
            
                //4.将class文件中的内容,动态加载到JVM中来
                
                //5.返回被代理后的代理对象
                Class proxyClass = classLoader.findClass("$Proxy0");
                Constructor c = proxyClass.getConstructor(GPInvocationHandler.class);  //拿到构造方法
                f.delete();
                
                return c.newInstance(h);
                
            }catch (Exception e) {
                e.printStackTrace();
            }
            
            
            return null;
        }
        
        
        private static String generateSrc(Class<?> interfaces){
            StringBuffer src = new StringBuffer();
            src.append("package com.gupaoedu.vip.custom;" + ln);
            src.append("import java.lang.reflect.Method;" + ln);
            src.append("public class $Proxy0 implements " + interfaces.getName() + "{" + ln);
            
            src.append("GPInvocationHandler h;" + ln);
            
            src.append("public $Proxy0(GPInvocationHandler h) {" + ln);
            src.append("this.h = h;" + ln);
            src.append("}" + ln);
            
            for (Method m : interfaces.getMethods()) {    //那么多方法 需要拿出来 
                src.append("public " + m.getReturnType().getName() + " " + m.getName() + "(){" + ln);
                
                src.append("try{" + ln);
                src.append("Method m = " + interfaces.getName() + ".class.getMethod("" +m.getName()+"",new Class[]{});" + ln);  //方法名 参数等等
                src.append("this.h.invoke(this,m,null);" + ln);  
                src.append("}catch(Throwable e){e.printStackTrace();}" + ln);
                src.append("}" + ln);    
            }  
            
            src.append("}");
            
            return src.toString();
        }
    }
    复制代码

    classloader类

    复制代码
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    
    //代码生成、编译、重新动态load到JVM
    public class GPClassLoader extends ClassLoader{
    
        private File baseDir;
        
        public GPClassLoader(){
            String basePath = GPClassLoader.class.getResource("").getPath();
            this.baseDir = new java.io.File(basePath);   //保存路径
        }
        
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            String className = GPClassLoader.class.getPackage().getName() + "." + name;   //找到这个class文件
            if(baseDir != null){
                File classFile = new File(baseDir,name.replaceAll("\.", "/") + ".class");
                if(classFile.exists()){
                    FileInputStream in = null;
                    ByteArrayOutputStream out = null; 
                    try{
                        in = new FileInputStream(classFile);
                        out = new ByteArrayOutputStream();
                        byte [] buff = new byte[1024];   //缓冲区
                        int len;
                        while ((len = in.read(buff)) != -1) {
                            out.write(buff, 0, len);
                        }  //全部读完
                        return defineClass(className, out.toByteArray(), 0,out.size());  //搞到jvm中去
                        
                    }catch (Exception e) {
                        e.printStackTrace();
                    }finally{
                        if(null != in){
                            try {
                                in.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                        if(null != out){
                            try {
                                out.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                        classFile.delete();
                    }
                    
                }
            }
            
            return null;
        }
        
    }
    复制代码

    代理类媒婆  必须实现这个类

    复制代码
    import java.lang.reflect.Method;
    
    import com.gupaoedu.vip.proxy.jdk.Person;
    
    public class GPMeipo implements GPInvocationHandler{
        
        private Person target;
        
        //获取被代理人的个人资料
        public Object getInstance(Person target) throws Exception{
            this.target = target;
            Class clazz = target.getClass();
            System.out.println("被代理对象的class是:"+clazz);
            return GPPorxy.newProxyInstance(new GPClassLoader(), clazz.getInterfaces(), this);
        }
        
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("我是媒婆:得给你找个异性才行");
            System.out.println("开始进行海选...");
            System.out.println("------------");
            method.invoke(this.target, args);
            System.out.println("------------");
            System.out.println("如果合适的话,就准备办事");
            return null;
        }
    
    }
    复制代码

    注意 Java中 $符号的 约定俗成 被代理的类

     JDK 必须 实现接口!!!!

    满足代理模式应用场景的三个必要条件,

        1、需要有两个角色  执行者 和 被代理对象

        2、注重过程,必须要做,被代理对象不做

       3、执行者必须拿到被代理对象的资料(执行者持有被代理对象的引用)

    代理模式总结到底层就是:字节码重组! (字节码重组时候 对象要强制转换,必须要实现一个接口)

     Java源代码--->编译---->字节码(在原始的加了东西)-->加载到jvm中 

    然后 cglib不需要,Spring主要用的cglib做动态代理 定义一个类   自动生成一个类 自动继承这个类 子类引用指向父类   看下面:

    (同样做了字节码重组 事情)

     是继承关系 

    复制代码
    public class YunZhongYu {
        
        
        public void findLove(){
            System.out.println("肤白貌美大长腿");
        }
        
    }
    复制代码

    定义代理类:

    复制代码
    import java.lang.reflect.Method;
    
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    public class GPMeipo implements MethodInterceptor{      // MethodInterceptor这是cglib里面的
    
        //疑问?
        //好像并没有持有被代理对象的引用
        public Object getInstance(Class clazz) throws Exception{
              //通过反射机制进行实例化
    
            Enhancer enhancer = new Enhancer();   //用来动态生成class
            //把父类设置为谁?
            //这一步就是告诉cglib,生成的子类需要继承哪个类
            enhancer.setSuperclass(clazz);
            //设置回调
            enhancer.setCallback(this);   //业务逻辑 指的是下面的 intercept 回调方法
            
            //第一步、生成源代码
            //第二步、编译成class文件
            //第三步、加载到JVM中,并返回被代理对象
            return enhancer.create();
        }
        
        //同样是做了字节码重组这样一件事情
        //对于使用API的用户来说,是无感知
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {    //要干的哪些事情   obj是生成以后的子类的引用   调用子类的引用就会调用这个子 intercept方法 调用super方法
            System.out.println("我是GP媒婆:" + "得给你找个异性才行");
            System.out.println("开始进行海选...");
            System.out.println("------------");
            //这个obj的引用是由CGLib给我们new出来的
            //cglib new出来以后的对象,是被代理对象的子类(继承了我们自己写的那个类)
            //OOP, 在new子类之前,实际上默认先调用了我们super()方法的,
            //new了子类的同时,必须先new出来父类,这就相当于是间接的持有了我们父类的引用
            //子类重写了父类的所有的方法
            //我们改变子类对象的某些属性,是可以间接的操作父类的属性的
            proxy.invokeSuper(obj, args);  //可以直接调用 调用的是父类哦
            System.out.println("------------");
            System.out.println("如果合适的话,就准备办事");
            return null;
        }
    
    }
    复制代码

    测试类

    复制代码
    public class TestGglibProxy {
        
        public static void main(String[] args) {
            
            //JDK的动态代理是通过接口来进行强制转换的
            //生成以后的代理对象,可以强制转换为接口
            
            
            //CGLib的动态代理是通过生成一个被代理对象的子类,然后重写父类的方法
            //生成以后的对象,可以强制转换为被代理对象(也就是用自己写的类)
            //子类引用赋值给父类
            
            
            try {
                YunZhongYu obj = (YunZhongYu)new GPMeipo().getInstance(YunZhongYu.class);  //面向接口 对外开放 制定规范  接口就是规范  一般是是字符串 包名 类名 方法名之类的
                obj.findLove();
            } catch (Exception e) {
                e.printStackTrace();
            }
            
        }
    }
    复制代码

    代理可以实现 在每一个方法调用之前加一些代码,方法嗲用之后加一些代码

    AOP: 事务代理、 日志监听

    Service方法  开启一个事务   事务的执行是由我们自己的代码完成的 

       1、监听到是否有异常,可能需要根据异常的类型来决定这个事务是否好回滚or继续提交?(commit or rollback?)

       2、事务要关闭掉 

    通过动态代理给加了代码   

    -------------------------------------工厂模式

    首先要区分 生产者 消费者     消费者不关心工厂、过程  只关心结果  从工厂取东西哈哈

    简单工厂:

    定义接口:

    复制代码
    //产品接口
    //汽车需要满足一定的标准
    public interface Car {
        
        //规定汽车的品牌
        String getName();
        
    }
    复制代码

    实现之:

    复制代码
    public class Bmw implements Car{
    
        @Override
        public String getName() {
            return "BMW";
        }
    
    }
    复制代码
    复制代码
    public class Benz implements Car{
    
        @Override
        public String getName() {
            return "Benz";
        }
    
    }
    复制代码
    复制代码
    public class Audi implements Car{
    
        @Override
        public String getName() {
            return "Audi";
        }
    
    }
    复制代码

    定义工厂类

    复制代码
    import com.gupaoedu.vip.factory.Audi;
    import com.gupaoedu.vip.factory.Benz;
    import com.gupaoedu.vip.factory.Bmw;
    import com.gupaoedu.vip.factory.Car;
    
    //对于这个工厂来说(太强大了)
    //为什么?
    //这个工厂啥都能干(不符合现实)
    //编码也是一种艺术(融汇贯通),艺术来源于生活,回归到生活的
    public class SimpleFactory {
        
        //实现统一管理、专业化管理
        //如果没有工厂模式,小作坊,没有执行标准的
        //如果买到三无产品(没有标准)
        //卫生监督局工作难度会大大减轻
        
        //中国制造(按人家的标准执行)
        //中国制造向中国创造改变(技术不是问题了,问题是什么?思维能力)
        //码农就是执行标准的人
        //系统架构师,就是制定标准的人
        
        //不只做一个技术者,更要做一个思考者
        
        
        public Car getCar(String name){
            if("BMW".equalsIgnoreCase(name)){
                //Spring中的工厂模式
                //Bean
                //BeanFactory(生成Bean)
                //单例的Bean
                //被代理过的Bean
                //最原始的Bean(原型)
                //List类型的Bean
                //作用域不同的Bean
                
                //getBean
                //非常的紊乱,维护困难
                //解耦(松耦合开发)
                return new Bmw();
            }else if("Benz".equalsIgnoreCase(name)){
                return new Benz();
            }else if("Audi".equalsIgnoreCase(name)){
                return new Audi();
            }else{
                System.out.println("这个产品产不出来");
                return null;
            }
        }
        
    }
    复制代码

    测试类(消费者)

    复制代码
    public class SimpleFactoryTest {
    
        
        
        public static void main(String[] args) {
        
            //这边就是我们的消费者
            Car car = new SimpleFactory().getCar("Audi");
            System.out.println(car.getName());
            
        }
        
    }
    复制代码

    接下来是 工厂方法模式

      定义工厂接口

      实现不同工厂

       消费者使用

    1、定义工厂接口

    复制代码
    import com.gupaoedu.vip.factory.Car;
    
    //工厂接口,就定义了所有工厂的执行标准
    public interface Factory {
    
        //符合汽车上路标准
        //尾气排放标准
        //电子设备安全系数
        //必须配备安全带、安全气囊
        //轮胎的耐磨程度
        Car getCar();
        
    }
    复制代码

    2、实现这个工厂接口

    复制代码
    import com.gupaoedu.vip.factory.Bmw;
    import com.gupaoedu.vip.factory.Car;
    
    public class BmwFactory implements Factory {
    
        @Override
        public Car getCar() {
            return new Bmw();
        }
    
    }
    复制代码
    复制代码
    import com.gupaoedu.vip.factory.Benz;
    import com.gupaoedu.vip.factory.Car;
    
    public class BenzFactory implements Factory {
    
        @Override
        public Car getCar() {
            return new Benz();
        }
    
    }
    复制代码

    3、测试类

    复制代码
    public class FactoryTest {
    
        public static void main(String[] args) {
            
            //工厂方法模式
            //各个产品的生产商,都拥有各自的工厂
            //生产工艺,生成的高科技程度都是不一样的
            Factory factory = new AudiFactory();
            System.out.println(factory.getCar());
            
            //需要用户关心,这个产品的生产商
            factory = new BmwFactory();
            System.out.println(factory.getCar());
            
            //增加的代码的使用复杂度
            
            
            //抽象工厂模式
            
        }
        
    }
    复制代码

    改进版的工厂方法模式,抽象工厂模式:

    这个不再是 接口了 而是 抽象类

     抽象类可以引用自己的方法! 

    默认的方法

    复制代码
    import com.gupaoedu.vip.factory.Car;
    
    public class DefaultFactory extends AbstractFactory {
    
        private AudiFactory defaultFactory = new AudiFactory();
        
        public Car getCar() {
            return defaultFactory.getCar();
        }
    
    }
    复制代码

    工厂方法

    复制代码
    import com.gupaoedu.vip.factory.Car;
    
    public abstract class AbstractFactory {
    
         protected abstract Car getCar();
         
         
         //这段代码就是动态配置的功能
         //固定模式的委派
         public Car getCar(String name){
            if("BMW".equalsIgnoreCase(name)){
                return new BmwFactory().getCar();
            }else if("Benz".equalsIgnoreCase(name)){
                return new BenzFactory().getCar();
            }else if("Audi".equalsIgnoreCase(name)){
                return new AudiFactory().getCar();
            }else{
                System.out.println("这个产品产不出来");
                return null;
            }
        }
    
    }
    复制代码
    复制代码
    import com.gupaoedu.vip.factory.Audi;
    import com.gupaoedu.vip.factory.Car;
    
    
    //具体的业务逻辑封装
    public class AudiFactory extends AbstractFactory {
    
        @Override
        public Car getCar() {
            return new Audi();
        }
    
    }
    复制代码
    复制代码
    public class BenzFactory extends AbstractFactory {
    
        @Override
        public Car getCar() {
            return new Benz();
        }
    
    }
    复制代码
    复制代码
    public class BmwFactory extends AbstractFactory {
    
        @Override
        public Car getCar() {
            return new Bmw();
        }
    
    }
    复制代码

    单例模式:

    整个系统从启动到终止,自会有一个实例

    在应用中遇到功能性冲突的时候,需要用到单例模式

    单例模式有7种写 法!!!

    1.

    复制代码
    1 public class Singleton implements java.io.Serializable {   
    2     public static Singleton INSTANCE = new Singleton();   
    3     protected Singleton() {  }   
    4     private Object readResolve() {   
    5         return INSTANCE;   
    6     }
    7 }
    复制代码

    2、

    复制代码
    //懒汉式单例类.在第一次调用的时候实例化自己
    public class Singleton1 {
        //1、第一步先将构造方法私有化
        private Singleton1() {}
        //2、然后声明一个静态变量保存单例的引用
        private static Singleton1 single = null;
        //3、通过提供一个静态方法来获得单例的引用
        //不安全的
        public static Singleton1 getInstance() {
            if (single == null) {
                single = new Singleton1();
            }
            return single;
        }
    }
    复制代码

    3、

    复制代码
    //懒汉式单例.保证线程安全
    public class Singleton2 {
        //1、第一步先将构造方法私有化
        private Singleton2() {}
        //2、然后声明一个静态变量保存单例的引用
        private static Singleton2 single=null;
        //3、通过提供一个静态方法来获得单例的引用
        //为了保证多线程环境下正确访问,给方法加上同步锁synchronized
        //慎用  synchronized 关键字,阻塞,性能非常低下的
        //加上synchronized关键字以后,对于getInstance()方法来说,它始终单线程来访问
        //没有充分利用上我们的计算机资源,造成资源的浪费
        public static synchronized Singleton2 getInstance() {
            if (single == null) {
                single = new Singleton2();
            }
            return single;  
        }
    }
    复制代码

    4、

    复制代码
    //懒汉式单例.双重锁检查
    public class Singleton3 {
        //1、第一步先将构造方法私有化
        private Singleton3() {}
        //2、然后声明一个静态变量保存单例的引用
        private static Singleton3 single=null;
        //3、通过提供一个静态方法来获得单例的引用
        //为了保证多线程环境下的另一种实现方式,双重锁检查
        //性能,第一次的时候
        public static Singleton3 getInstance() {  
          if (single == null) {
              synchronized (Singleton3.class) {
                  if (single == null) {    
                      single = new Singleton3();
                  }    
              }    
          }    
           return single;   
        }
    }
    复制代码

    5、

    复制代码
    //懒汉式(静态内部类)
    //这种写法,即解决安全问题,又解决了性能问题
    //这个代码,没有浪费一个字
    public class Singleton4 {
        //1、先声明一个静态内部类
        //private 私有的保证别人不能修改
        //static 保证全局唯一
        private static class LazyHolder {
            //final 为了防止内部误操作,代理模式,GgLib的代理模式
            private static final Singleton4 INSTANCE = new Singleton4();
        }
        //2、将默认构造方法私有化
        private Singleton4 (){}
        //相当于有一个默认的public的无参的构造方法,就意味着在代码中随时都可以new出来
            
        //3、同样提供静态方法获取实例
        //final 确保别人不能覆盖
        public static final Singleton4 getInstance() {  
            
            //方法中的逻辑,是要在用户调用的时候才开始执行的
            //方法中实现逻辑需要分配内存,也是调用时才分配的
            return LazyHolder.INSTANCE;
        }
        
    //    static int a = 1;
    //    //不管该class有没有实例化,static静态块总会在classLoader执行完以后,就加载完毕
    //    static{
    //        //静态块中的内容,只能访问静态属性和静态方法
    //        //只要是静态方法或者属性,直接可以用Class的名字就能点出来
    //        Singleton4.a = 2;
    //        //JVM 内存中的静态区,这一块的内容是公共的 
    //    }
    }
    
    //我们所写的所有的代码,在java的反射机制面前,都是裸奔的
    //反射机制是可以拿到private修饰的内容的
    //我们可以理解成即使加上private也不靠谱(按正常套路出牌,貌似可以)
    
    
    //类装载到JVM中过程
    //1、从上往下(必须声明在前,使用在后)
    //先属性、后方法
    //先静态、后动态
    复制代码

    6、

    复制代码
      //类似Spring里面的方法,将类名注册,下次从里面直接获取。  
    public class Singleton6 {  
        private static Map<String,Singleton6> map = new HashMap<String,Singleton6>();  
        static {
            Singleton6 single = new Singleton6();
            map.put(single.getClass().getName(), single);
        }
        //保护的默认构造子  
        protected Singleton6(){}  
        //静态工厂方法,返还此类惟一的实例  
        public static Singleton6 getInstance(String name) {  
            if(name == null) {  
                 name = Singleton6.class.getName();  
            }  
            if(map.get(name) == null) {  
           try {  
               map.put(name, (Singleton6) Class.forName(name).newInstance());  
           } catch (InstantiationException e) {  
               e.printStackTrace();  
           } catch (IllegalAccessException e) {  
               e.printStackTrace();  
           } catch (ClassNotFoundException e) {  
               e.printStackTrace();  
           }  
    }  
    return map.get(name);  
    }  
    }
    复制代码

    测试类

    复制代码
    public class TestMain {
        public static void main(String[] args){  
            TestSingleton ts1 = TestSingleton.getInstance();  
            ts1.setName("james");  
            TestSingleton ts2 = TestSingleton.getInstance();  
            ts2.setName("tom");  
              
            ts1.printInfo();  
            ts2.printInfo();  
              
            if(ts1 == ts2){  
                System.out.println("创建的是同一个实例" + ts1.getName());  
            }else{  
                System.out.println("创建的不是同一个实例" + ts1.getName());  
            }  
        }
    }
    复制代码
    复制代码
    public class TestSingleton {  
        String name = null;  
        private TestSingleton() {}  
      
        //注意这里用到了volatile关键字
        private static volatile TestSingleton instance = null;  
      
        public static TestSingleton getInstance() {  
           if (instance == null) {    
             synchronized (TestSingleton.class) {    
                if (instance == null) {    
                   instance = new TestSingleton();   
                }    
             }    
           }   
           return instance;  
        }  
      
        public String getName() {  
            return name;  
        }  
      
        public void setName(String name) {  
            this.name = name;  
        }  
      
        public void printInfo() {  
            System.out.println("the name is " + name);  
        }  
      
    }
    复制代码
    复制代码
    public class TestThread {
        
        public static void main(String[] args) {
            //启动100线程同时去抢CPU
            int count = 100;
            
            //发令枪,测试并发经常用到
            CountDownLatch latch = new CountDownLatch(count);
            //Set默认去去重的,set是本身线程不安全的
            //
            final Set<Singleton1> syncSet = Collections.synchronizedSet(new HashSet<Singleton1>());
            
            for (int i = 0; i < count; i++) {
                new Thread(){
    
                    @Override
                    public void run() {
                        syncSet.add(Singleton1.getInstance());
                    }
                }.start();
                
                latch.countDown();
            }
              
            try {
                latch.await();//等待所有线程全部完成,最终输出结果
                System.out.println(syncSet.size());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
    }
    复制代码

    委派模式:

     1类似中介的功能(委托机制)

     2只有被委托人的引用 

    两个角色 受托人 委托人

     定义一个接口

    复制代码
    public class Dispatcher implements IExector{
        IExector exector;
        
        Dispatcher(IExector exector){
            this.exector = exector;
        }
        
        
        //项目经理,虽然也有执行方法
        //但是他的工作职责是不一样的
        public void doing() {
            this.exector.doing();
        }
    
    }
    复制代码

    两个员工类实现这个接口

    复制代码
    public class ExectorA implements IExector {
    
        @Override
        public void doing() {
            System.out.println("xxoo");
        }
    
    }
    复制代码
    复制代码
    public class ExectorB implements IExector{
    
        @Override
        public void doing() {
            System.out.println("员工B开始执行任务");
        }
    
    }
    复制代码

    项目经理类

    复制代码
    public class Dispatcher implements IExector{
        IExector exector;
        
        Dispatcher(IExector exector){
            this.exector = exector;
        }
        
        
        //项目经理,虽然也有执行方法
        //但是他的工作职责是不一样的
        public void doing() {
            this.exector.doing();
        }
    
    }
    复制代码

    测试

    复制代码
    public class DispatcherTest {
    
        
        public static void main(String[] args) {
            Dispatcher dispatcher = new Dispatcher(new ExectorA());
            //看上去好像是我们的项目经理在干活
            //但实际干活的人是普通员工
            //这就是典型,干活是我的,功劳是你的
            dispatcher.doing();
        }
        
    }
    复制代码

    IOC容器中,有一个Register的东西(为了告诉我们的容器,在这个类被初始化的过程中,需要做很多不同的逻辑处理,需要实现多个任务执行者,分别实现各自的功能 )

    关于策略模式,参考系 Comparator方法就可以啦 返回  -1 0 1这种的

      a、比较器接口

      b、调用时候有自己的实现

    复制代码
    //比较器
    public interface Comparator {
        
        int compareTo(Object obj1,Object obj2);
        
    }
    复制代码
    复制代码
    public class ObjectComparator implements Comparator{
    
        @Override
        public int compareTo(Object obj1, Object obj2) {
            return 0;
        }
    
    }
    复制代码
    复制代码
    public class NumberComparator implements Comparator{
    
        @Override
        public int compareTo(Object obj1, Object obj2) {
            return 0;
        }
    
    }
    复制代码
    复制代码
    public class MyList {
        
        public void sort(Comparator com){
    //        com.compareTo(obj1, obj2);
            System.out.println("执行逻辑");
        }
        
    }
    复制代码
    复制代码
    public class MyListTest {
        
        public static void main(String[] args) {
            //new MyList().sort(new NumberComparator());
            
            
            //策略模式
    //        List<Long> numbers = new ArrayList<Long>();
    //        
    //        Collections.sort(numbers, new Comparator<Long>() {
    //
    //            @Override
    //            //返回值是固定的
    //            //0 、-1 、1
    //            //0 、 >0 、<0
    //            public int compare(Long o1, Long o2) {
    //                
    //                //中间逻辑是不一样的
    //                
    //                return 0;
    //            }
    //            
    //            
    //        });
        }
    }
    复制代码

     原型模式:  

      首先要设计个原型

        实现 Cloneable接口

    复制代码
    public class ConcretePrototype implements Cloneable{
    
        private int age;
    
        private String name;
        
        public ArrayList<String> list = new ArrayList<String>();
        
        protected Object clone() throws CloneNotSupportedException {
            ConcretePrototype prototype = null;
            try{
                prototype = (ConcretePrototype)super.clone();
                prototype.list = (ArrayList)list.clone();
                
                //克隆基于字节码的
                //用反射,或者循环
            }catch(Exception e){
                
            }
            
            return prototype;
        }
    
        
        //定义上100个属性
        
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        
        
        
        
    }
    复制代码
    复制代码
    public class CloneTest {
    
        
        
        public static void main(String[] args) {
            
            ConcretePrototype cp = new ConcretePrototype();
            cp.setAge(18);
            cp.setName("Tom");
            
            //cp.list.add("Tom");
            
            try {
                ConcretePrototype copy = (ConcretePrototype)cp.clone();
                
                System.out.println(copy.list  == cp.list);
                System.out.println(copy.getAge() + "," + copy.getName() + copy.list.size());
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            
            //就是一个现成的对象,这个对象里面有已经设置好的值
            //当我要新建一个对象,并且要给新建的对象赋值,而且赋值内容要跟之前的一模一样
            
            
            //ConcretePrototype cp = new ConcretePrototype();
            //cp.setAge(18);
            
            //ConcretePrototype copy = new ConcretePrototype();
            //copy.setAge(cp.getAge());
            //copy.setName(cp.getName());
            //用循环,用反射,确实可以的(反射性能并不高)
            //字节码复制newInstance()
            
            //ConcretePrototype copy = cp;
            //ORM的时候经常用到的
            
            
            //能够直接拷贝其实际内容的数据类型/只支持9种,八大基本数据类型+String 浅拷贝
            //深拷贝
        }
        
    }
    复制代码

    原型模式:

    复制代码
    //猴子
    public class Monkey {
        //身高
        protected int height;//基本
        //体重
        protected int weight;
        //生日
        protected Date birthday;//不是基本类型
        
        public int getHeight() {
            return height;
        }
        public void setHeight(int height) {
            this.height = height;
        }
        public int getWeight() {
            return weight;
        }
        public void setWeight(int weight) {
            this.weight = weight;
        }
        public Date getBirthday() {
            return birthday;
        }
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    
    
        
        
    }
    复制代码
    复制代码
    public class TestPrototype {
        public static void main(String[] args) {
            TheGreatestSage sage = new TheGreatestSage();
            sage.change();
            
            //跟《西游记》中描述的一致,怎么办?
        }
    }
    复制代码
    复制代码
    public class GoldRingedStaff implements Serializable{
        
        private float height = 100; //长度
        private float diameter = 10;//直径
        
        
        
        /**
         * 金箍棒长大
         */
        public void grow(){
            this.diameter *= 2;
            this.height *= 2;
        }
        
        /**
         * 金箍棒缩小
         */
        public void shrink(){
            this.diameter /= 2;
            this.height /= 2;
        }
        
    }
    复制代码
    复制代码
    /**
     * 齐天大圣
     *
     */
    public class   TheGreatestSage  extends Monkey implements Cloneable,Serializable{
        
        //金箍棒
        private GoldRingedStaff staff;
        
        //从石头缝里蹦出来
        public TheGreatestSage(){
            this.staff = new GoldRingedStaff();
            this.birthday = new Date();
            this.height = 150;
            this.weight = 30;
            System.out.println("------------------------");
        }
        
        //分身技能
        public Object clone(){
            //深度克隆
            ByteArrayOutputStream bos = null;
            ObjectOutputStream oos = null;
            ByteArrayInputStream bis = null;
            ObjectInputStream ois = null;
            try {
                //return super.clone();//默认浅克隆,只克隆八大基本数据类型和String
                //序列化
                bos = new ByteArrayOutputStream();
                oos = new ObjectOutputStream(bos);
                oos.writeObject(this);
                
                //反序列化
                bis = new ByteArrayInputStream(bos.toByteArray());
                ois = new ObjectInputStream(bis);
                TheGreatestSage copy = (TheGreatestSage)ois.readObject();
                copy.birthday = new Date();
                
                return copy;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }finally{
                try {
                    bos.close();
                    oos.close();
                    bis.close();
                    ois.close();
                    
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        //变化
        public void change(){
            TheGreatestSage copySage = (TheGreatestSage)clone();
            System.out.println("大圣本尊生日是:" + this.getBirthday().getTime());
            System.out.println("克隆大圣的生日是:" + copySage.getBirthday().getTime());
            System.out.println("大圣本尊和克隆大圣是否为同一个对象:" + (this == copySage));
            System.out.println("大圣本尊持有的金箍棒跟克隆大圣持有金箍棒是否为同一个对象:" + (this.getStaff() == copySage.getStaff()));
        }
        
        public GoldRingedStaff getStaff() {
            return staff;
        }
    
        public void setStaff(GoldRingedStaff staff) {
            this.staff = staff;
        }
        
        
        
        
    }
    复制代码

    模板模式:

    模板(固定的执行流程)

    定义冲饮料的机器:

    复制代码
    //冲饮料(拿出去卖钱了)
    public abstract class Bevegrage {
        
        //不能被重写
        public final void create(){
            //1、把水烧开
            boilWater();
            //2、把杯子准备好、原材料放到杯中
            pourInCup();
            //3、用水冲泡
            brew();
            //4、添加辅料
            addCoundiments();
        }
        
        public abstract void pourInCup();
        
        public abstract void addCoundiments();
        
        
        public void brew(){
            System.out.println("将开水放入杯中进行冲泡");
        };
        
        public void boilWater(){
            System.out.println("烧开水,烧到100度可以起锅了");
        }
        
    }
    复制代码

    实现为冲咖啡的

    复制代码
    public class Coffee  extends Bevegrage{
    
        //原材料放到杯中
        public void pourInCup() {
            System.out.println("将咖啡倒入杯中");
        }
    
        //房辅料
        public void addCoundiments() {
            System.out.println("添加牛奶和糖");
        }
    
    }
    复制代码

    实现为泡茶的

    复制代码
    public class Tea extends Bevegrage{
    
        //原材料放到杯中
        public void pourInCup() {
            System.out.println("将茶叶放入杯中");
        }
    
        //房辅料
        public void addCoundiments() {
            System.out.println("添加蜂蜜");
        }
    
    }
    复制代码

    测试类

    复制代码
    public class TestTemplate {
        
        public static void main(String[] args) {
            
    //        Coffee coffee = new Coffee();
    //        coffee.create();
            
            Tea tea = new Tea();
            tea.create();
            
        }
        
        
        //SpringJDBC
        //是java规范,各个数据库厂商自己去实现
        //1、加载驱动类DriverManager
        //2、建立连接
        //3、创建语句集(标准语句集、预处理语句集)(语句集?  MySQL、Oracle、SQLServer、Access)
        //4、执行语句集
        //5、结果集ResultSet 游标
        //ORM(?)
        
    }
    复制代码

    Spring JDBC就是个模板模式

    是 Java的规范  各个数据库厂商去实现

      1、加载驱动类 DriverManager

       2、建立连接

       3、创建语句集(标准语句集、预处理语句集)(语句集合? Mysql oracle sqlserver access 语句不太一样哦)

       4、执行语句集

        5、结果集ResultSet 游标

       ORM (连接的是哪个对象 映射哪个结果 List or 自定义的类 还是??运行时候才知道)

    https://www.cnblogs.com/toov5/p/9472082.html

  • 相关阅读:
    程序员常去的14个顶级开发社区
    为何技术领域中女程序员较少?
    为何技术领域中女程序员较少?
    为何技术领域中女程序员较少?
    关于HTTP和HTTPS的区别
    关于HTTP和HTTPS的区别
    关于HTTP和HTTPS的区别
    Coupled model
    java和javascript日期详解
    Java 线程总结(十四)
  • 原文地址:https://www.cnblogs.com/langtianya/p/10206884.html
Copyright © 2011-2022 走看看