框架底层核心知识点分析总结
   一些代码   0 评论   1743 浏览

框架底层核心知识点分析总结

   一些代码   0 评论   1743 浏览

反射

什么是反射

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

简单理解反射:

通过class文件对象(Class对象、字节码文件对象),去创建类对象、使用其构造方法、成员函数和成员方法,
然后通过反射得到的对象Method,Fielde等对象,反过来执行类中的方法和属性。

反射常用的api

三个方法获取类对象

获取class文件对象的方法:

分别使用以上三个方法获取Class对象,讲解过程中强调一下几点(及其原因):

学习了三种方法以后,我们在开发中到底用哪个呢?

通过Class可以获取类中的方法对象

Method[] methods = c.getMethods();// 所有公共方法,包括父类的
Method[] methods = c.getDeclaredMethods();// 本类的所有方法
Method  method = c.getMethod(方法名称,方法的形参类型)

获取方法对象的目的,就是反过来去执行类的中的方法。比如:

反射得到类的实例化对象

Class  clazz = Class类的方法forName(className)
Object obj = clazz.newInstance();//默认通过无参的构造,实例化该类的对象

比如:

总结:为什么要使用反射?

总结:

底层使用的设计模式

设计模式介绍

一个系统的整个架构,怎么分块、分层、分包,开发完成后怎么集成、怎么测试,怎么让程序的拓展性更好,这些时候就需要考虑到设计模式。好多人不知道学了这些东西应该往哪里用,其实我们现在学的一些东西就已经用到了设计模式,只是我们不知道。所以现在我们先了解了解,回头可以好好研究研究。

我们先从字面上理解一下,什么是设计模式。

一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。

使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。

举例说明上面的概念:建房子可以建各种各样的,一层平房、两层复式。如果你想建房子,看我的不错,可以把我的设计图纸拿走对比着去建,这就是现实生活中的设计模式。

刚才说了,房子有一层两层,平房复式,那么java中的设计模式也是有分类的。详细讲解并举例下面的三种分类

单列模式(多)

单列模式概述

单一实例模式(唯一实例模式)

举列:打印机服务(在一台机子上),ATM取款(在一台机子上)

应用场景:数据库连接池对象(连接池对象唯一),Servlet对象(唯一)

作用:单列模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在。 使用Singleton的好处还在于可以节省内存,因为它限制了实例的个数,有利于Java垃圾回收

单列模式的实现

单列模式实现的要求

饿汉式单列模式:

public class Singleton {   
 private static Singleton singleton = new Singleton();//立即实例化对象
    private Singleton() {}//私有化构造方法
    public static Singleton  getSignleton(){//对外提供方法得到单列对象
        return singleton;
    }
}

懒汉式单列模式:

懒汉模式只在外部对象第一次请求实例的时候才去创建

public class Singleton {
    private static Singleton singleton = null;
    private Singleton(){}
    public static Singleton getSingleton(){
            if(singleton == null){
                singleton = new Singleton();//延迟创建对象
            }
            return singleton;
    }    
}

Spring框架中用到了单列模式,比如:

< bean id="userDao" class="com.rawchen.UserDaoImpl" scope="singleton" ></bean>

当然了,有单列模式,自然会有多列,就是可以创建多个对象,具体采用单列或者多列,

要看我们实际开发中的需要了。

工厂模式(多)

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。

这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

通俗的来讲就是:

简单工厂的实现方式

比如:

我们需要猫狗这些动物的对象,因为这些对象有共性,所以我们抽取出来的了公共父类Animal。因为每次创建对象我们都自己new太麻烦,所以我们想让工厂帮我们做,所以又提供了一个AnimalFactory,并提供了createAnimal方法,我们想要什么对象,就给该方法传递相应的参数,他就能返回相应的对象。

简单工厂模式:
    Animal
        |--Dog
        |--Cat
        
    AnimalFactory
        public static Animal createAnimal(String type)
/**
    定义一个接口:动物接口
 */
public interface Animal {
    public void eat();
}
//Cat类
public class Cat implements  Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼---");
    }
}
//Dog类
public class Dog implements  Animal {
    @Override
    public void eat() {
        System.out.println("狗吃骨头-------");
    }
}
/*
    工厂类对象:创建对象
    之前自己创建对象,现在把对象的创建权交个工厂
 */
public class AnimalFactory {
    /*
        提供一个方法:创建对象
     */
    public static  Animal getBean(String type){
        if("dog".equals(type)){
            return new Dog();
        }else if("cat".equals(type)){
            return new Cat();
        } else{
       return null;
    }
}

通过分析:
但是这种模式依然存在耦合关系,拓展性能不好(通过代码再详细讲解)。所以我们称之为简单工厂模式,
工厂里面也是通过new Dog()这样的方式创建对象的,使用起来不灵活。

工厂方法模式

在AnimalFactory工厂里添加一个方法如下:

/*
    通过反射+配置文件完成
    在这里,就不写配置文件了
    实际开发中:class对象是通过配置文件获取的
    比如:spring创建对象的方式
    <bean id="cat" class="cn.itheima.Cat" />
    <bean id="dog" class="cn.itheima.Dog" />
    通过配置文件获取 class, 能够动态去创建对象
 */
public static  Animal getBean(Class type) {
    try{
       Animal animal = (Animal) type.newInstance(); 
       return animal;
    }catch (Exception e){
        e.printStackTrace();
        return  null;
    } 
}

耦合关系,便于程序后期的扩展和维护。

工厂和单列小结:

装饰者模式

用的不多,主要用于比较代理模式

增强接口中实现类中的功能。

书写装饰类要求:

优点:

缺点:

与继承的区别:

装饰者模式和代理的比较总结:

需求:

代码比较:

装饰者模式的实现

需求:给手机打电话加一个彩铃功能

Phone(接口)
     |--PhoneImpl(具体实现类)
     |--PhoneDecorate(装饰者类)

代码实现:

public interface Phone {
    public abstract void call();
}

public class PhoneImpl implements Phone {

    @Override
    public void call() {
        System.out.println("用手机打电话");
    }
}
public  class PhoneDecorate implements Phone {
    private Phone phone; //具体的手机,多态
    public PhoneDecorate(Phone sendphone) {//构造方法,赋值 
        this.phone = sendphone 
    }
    @Override
    public void call() {
        //加彩铃功能 增强功能
        this.phone.call();//打电话
    }
}

分析:

装饰者虽然对类中的方法能进行增强,稍微比继承的方式灵活一点。

但是 最大的缺点是,需要重写接口的所有方法,即使该方法不需要增强。

也要把这个方法重写了。

所以 这种模式在框架中应用较少。

动态代理模式(多)

动态代理就是给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问

通俗的来讲:

比如:

实现方式:

动态代理分类

(1) JDK动态代理:sun官方提供的代理方式

通俗的来讲,如果使用JDK实现动态代理,必须提供接口,然后提供类实现接口

JDK就是通过接口给实现类进行代理的。

Spring默认使用JDK的动态代理

比如:

/*
    定义一个接口:
    通过代理:增强删除方法
    在调用删除方法之前,添加操作时间,操作人(记录日志)
 */
public interface UserService {
    public  void deleteUses();//删除数据
    public  void selectUses();//查询数据
}
public class UserServiceImpl implements UserService {
    @Override
    public void deleteUses() {
        System.out.println("执行删除数据---");
    }

    @Override
    public void selectUses() {

    }
}
public class Demo_JDK {
    public static void main(String[] args) {
        //1.创建UserService 实现类对象
        final UserService service = new UserServiceImpl();
        //2.创建代理对象,控制service对象(通俗的说增强里面的方法)
        UserService proxy  =(UserService) Proxy.newProxyInstance(Demo_JDK.class.getClassLoader(), service.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if(method.getName().contains("delete")){
                            //模拟增强效果
                            System.out.println("2019-5-22 12:24:36,小明执行删除操作");
                        }
                        return method.invoke(service,args);//如果没有增强,原路返回
                    }
             } );
        //3.调用方法
        // proxy.selectUses();//没有增强,
        proxy.deleteUses();//增强
    }
}

JDK动态代理总结:

动态代理的执行流程:

(2) CGLIB动态代理:第三方的代理方式

特点:

通俗的来讲:如果有一个类,CGLIB会给该类生成代理对象,完成对方法的增强

比如:

UserService 类

CGLIB会给该类生成一个代理对象,增强类中的方法。

/*
    定义一个类:
    通过代理:增强删除方法
    在调用删除方法之前,添加操作时间,操作人(记录日志)
 */
public class  UserService {
    public  void deleteUses(){//删除数据
        System.out.println("删除数据");
    };
    public  void selectUses(){//查询数据
    };
}
public class Cglib_Service  implements MethodInterceptor{
    //1.创建代理类对象:
    private Enhancer eh = new Enhancer();
    public Object  getProxyObj(Class clazz){//clazz指的就是真实类的字节码对象
        //1.1 引入真实类的clazz
        eh.setSuperclass(clazz);
        //1.2 回调方法对真实类进行反射: 把真实类的属性和方法反射成对应的对象:Field Method等
        eh.setCallback(this);
        //1.3 组装 :对真实类里面的属性和方法 进行重新组装,生成代理对象(代理类是真实类的子类)
        Object proxy = eh.create();
        return proxy;
    }

    /**
     *
     * @param objproxy:  代理对象
     * @param method:       sale
     * @param params: 方法里面的参数
         * @param methodProxy:CGLIB$sale$0():代理对象的方法
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object objproxy, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
        //1.对删除方法进行增强
        System.out.println("2019-5-22 15:36:36,小黑执行删除操作");
        //2.调用真实类的方法:通过组装的方法对象去调用
        Object obj = methodProxy.invokeSuper(objproxy,params);
        return obj;
    }
}
public class Demo_cglib {
    public static void main(String[] args) {
        //1创建UserService对象
        UserService service = new UserService();
        //2.通过cglib给 UserSerivce生成代理对象
        Cglib_Service cglib = new Cglib_Service();
        UserService proxyObj = (UserService) cglib.getProxyObj(service.getClass());
        proxyObj.deleteUses();
    }
}

总结:

动态代理相对于装饰者模式来说,更加灵活,不用重写接口中的方法,可以动态的完成

对方法的增强。

Spring进行事务管理时,会根据当前的是接口或者是类,来使用不同的代理方式。

JDK动态代理和CGLIB动态代理区别:

Spring框架在使用代理模式时,会根据当前java文件是类或者是接口,然后采用不同的代理方式,在spring4.0以后的版本(自动整合了cglib代理)

本文由 RawChen 发表, 最后编辑时间为:2021-11-13 13:20
如果你觉得我的文章不错,不妨鼓励我继续写作。

发表评论
选择表情
Top