实训一 框架底层分析,SpringBoot自动装配

一.设计模式

  1. 反射

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

    简单理解:

    反射:

    通过class文件对象(Class对象、字节码文件对象),去创建类对象、使用其构造方法、成员函数和成员方法,

    然后通过反射得到的对象Method,Fielde等对象,反过来执行类中的方法和属性。

1.1设计模式的分类

  • 创建型:创建对象。有:工厂模式、单例模式

  • 结构型:对象间的关系。有:装饰模式

  • 行为型:对象能够做什么。模板模式。

  • 增强型:对象除了做什么,还能额外做什么,有:代理模式

1.2常见的设计模式

1.2.1 单例模式: 在内存中保证创建一个对象。

  • 应用场景:在项目中,如果对象的状态没有改变,使用单列模式,反之使用多列模式

    比如:事务操作中,必须保证事务对象是同一个。

    比如:在请求操作中,请求对象必须是多个。

    /**
     * 单列模式:在内存中,保证使用的是同一个对象
     * 满足如下规范
     * 1.提供私有的无参构造方法
     * 2.对外提供一个获取对象的方法
     */
    //饿汉式写法: 立即创建对象
    public class A {
        //1.私有的构造方法
        private A(){
    ​
        }
        //2.提供一个方法:对外获取对象
        private  static  A a = new A();
        public static A getBean(){
            return  a;
        }
    }
    ​
    /**
     * 单列模式:在内存中,保证使用的是同一个对象
     * 满足如下规范
     * 1.提供私有的无参构造方法
     * 2.对外提供一个获取对象的方法
     */
    //懒汉式写法: 立即创建对象
    public class B {
        //1.私有的构造方法
        private B(){
    ​
        }
        //2.提供一个方法:对外获取对象
        private  static B b = null;
        public static B getBean(){
    ​
            if(b==null){
               b= new B();
            }
            return b;
        }
    }
    ​

1.2.2 工厂模式:加载配置文件,获取对象装到“容器中”。

  • 应用场景:通过工厂构建对象,解决程序中的耦合问题

  • ​
    /**
     * 简单工厂: 代码存在耦合问题依然存在。
     */
    public class Factory1 {
    ​
        //1.提供一个方法:创建对象
        public static Object getBean(Class z) throws Exception {
            return  z.newInstance();
        }
        //2.泛型:表示任意类型,解决类型强转问题
        public  static <T> T getBean2(Class z) throws Exception{
    ​
            T t = (T) z.newInstance();
            return  t;
        }
    }
    ​
    /**
     * 解决:耦合问题
     * 思路:配置文件+ 反射= Factoy2
     * 配置文件: xml (properties, yml)
     * 在配置文件加载完毕,把所有对象存到“容器中”
     * “容器”: 一般指的计算机的内存空间,直接的说通过集合或者数组保存对象,集合或者数组 就是容器
     */
    public class Factory3 {
        //1.加载配置文件
        private static Document document;
        //2.创建容器对象
        private  static Map<String,Object> map = new HashMap<String,Object>();
        static {
            try {
                //1.1.创建解析器对象
                SAXReader saxReader = new SAXReader();
                //1.2 获取配置文件的字节输入流
                InputStream in = Factory3.class.getClassLoader().getResourceAsStream("beans.xml");
                //1.3 获取文档对象
                document = saxReader.read(in);
                //1.4读取所有标签 获取id ,class
                List<Element> list = document.selectNodes("//bean");
                //1.5,把id作为map的key,把class反射后的对象作为value
                for (Element element : list) {
                    String key = element.attributeValue("id");// dog ,cat
                    Object value =Class.forName( element.attributeValue("class")).newInstance();
                    map.put(key,value);// dog--->Dog
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //2.创建对象:从容器中获取
        public static <T> T  getBean2(String idValue) throws Exception{
            return  (T)map.get(idValue);
        }
    ​
    ​
    }
    ​

    1.3 代理模式

    • 代理: 在开发中,给接口或者类进行代理,目的为了增强接口或者类中的方法。

    • 代理分类

      1. 基于jdk代理(sun提供): 基于接口代理,给接口生成一个代理类

      2. 基于第三方代理(cglib): 基于类进行代理,给当前类生成一个代理类

      3.  
         
        package cn.tedu.proxy_model;
        ​
        public interface Lenovo {
            void sellComputer(double money);
        }
        package cn.tedu.proxy_model;
        ​
        public class TagSeller implements Lenovo {
            @Override
            public void sellComputer(double money) {
                System.out.println("卖电脑:"+money );
            }
        }
        ​
        public class Demo4 {
            /**
             * jdk代理:基于接口代理,给接口生成一个代理类(代理类实现了该接口)
             * 比如:
             *     早前: 联想公司卖电脑
             *     代理商的模式:
             *              联想公司----》某个A省份代理商
             *              联想公司----》某个B省份代理商
             */
            @Test
            public void testX(){
                //1.生成代理类
                //参数一:类加载器(应用类加载器)
                ClassLoader loader = UserMapper.class.getClassLoader();
                //参数二:接口(提供接口)
                Class[] interfaces = {UserMapper.class};
                //参数三:增强器对象
                InvocationHandler handler = new InvocationHandler() {
                    // proxy : 代理对象, Method : 执行的方法, args: 执行方法的参数
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("执行sql前----检查sql语法是否正确");
                       Object obj = method.invoke(new UserMapper() {
                           @Override
                           public void addUser() {
                               System.out.println("真正的添加--执行sql");
                           }
                       }, args);// proxy.addUser();
                        System.out.println("执行sql后----处理结果");
                        return null;
                    }
                };
                UserMapper proxy = (UserMapper) Proxy.newProxyInstance(loader,interfaces,handler);
                proxy.addUser();
            }
        ​
            @Test
            public void testX2(){
                Lenovo tag = new TagSeller();
                Class[] interfaces = {Lenovo.class};
                Lenovo proxy =(Lenovo) Proxy.newProxyInstance(tag.getClass().getClassLoader(), interfaces, new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("来这买电脑,送优惠券--前置增强");
                        Double mm = (Double) args[0];
                        method.invoke(tag,mm.intValue()+200);//执行卖电脑的方法
                        System.out.println("买完电脑,车送你回家---后置增强");
                        return null;
                    }
                });
                proxy.sellComputer(800.00);
            }
        }
        ​

    • 应用场景

      • spring框架中: 默认使用jdk代理,选择cglib代理

      • springsecurity,shiro : 安全校验框架,基于cglib代理。

      • mybatis框架: 基于mapper接口开发,选择jdk代理


1.3根据设计模式分析--spring框架底层原理

  • spring底层创建bean对象时

    工厂模式,单列模式,代理模式等等

  • spring进行全注解开发时

    • 1.使用@Configuration标识当前类是一个配置类,替代配置文件的

    • 2.使用@ComponentScan(basePackages = "cn.tedu.bean_factory.pojo"),开启包扫描

      @Component: 创建一个普通的bean
      @Controller : 创建web层的bean
      @Service: 创建业务层对象
      @Repository: 创建dao层对象(@Mapper)
      /**
       * 配置类: 替代配置文件
       */
      @ComponentScan(basePackages = "cn.tedu.bean_factory.pojo")
      @Configuration
      public class SpringConfig {
      ​
      ​
      }

1.4 springBoot自动装配原理

1.4.1 如何开启包扫描

结论:

通过Registrar----》 AutoConfigurationPackages 扫描包(扫描启动类的包以及子包)自己创建的类以及sprigboot提供的必须bean

通过AutoConfigurationImportSelector----》ConfigurationClassBeanDefinitionReader-->springboot的jar/METE-INF/spring.properties

步骤一:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration//指定当前是一个配置类
public @interface SpringBootConfiguration {
}
步骤二:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage// 自动扫描包
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
​
    Class<?>[] exclude() default {};
​
    String[] excludeName() default {};
}
步骤三:
 @Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})//扫描包
public @interface AutoConfigurationPackage {
}
​
     static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
        Registrar() {
        }
​
        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());//1.开启包扫描 2.注入写的bean,提供必要bean
        }
​
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值