• Spring入门到进阶


    Spring的工厂类介绍

    public class SpringDemo1 {
    
        @Test
        /**
         * 传统方式开发
         */
        public void demo1(){
            // UserService userService = new UserServiceImpl();
            UserServiceImpl userService = new UserServiceImpl();
            // 设置属性:
            userService.setName("张三");
            userService.sayHello();
        }
    
        @Test
        /**
         * Spring的方式实现
         */
        public void demo2(){
            // 创建Spring的工厂
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
            // 通过工厂获得类:
            UserService userService = (UserService) applicationContext.getBean("userService");
    
            userService.sayHello();
        }
    
        @Test
        /**
         * 读取磁盘系统中的配置文件
         */
        public void demo3(){
            // 创建Spring的工厂类:
            ApplicationContext applicationContext = new FileSystemXmlApplicationContext("c:\applicationContext.xml");
            // 通过工厂获得类:
            UserService userService = (UserService) applicationContext.getBean("userService");
    
            userService.sayHello();
        }
    
        @Test
        /**
         * 传统方式的工厂类:BeanFactory
         */
        public void demo4(){
            // 创建工厂类:
            BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
            // 通过工厂获得类:
            UserService userService = (UserService) beanFactory.getBean("userService");
    
            userService.sayHello();
        }
    
        /**
         * 传统方式的工厂类:BeanFactory
         */
        @Test
        public void demo5(){
            // 创建工厂类:
            BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource("c:\applicationContext.xml"));
            // 通过工厂获得类:
            UserService userService = (UserService) beanFactory.getBean("userService");
    
            userService.sayHello();
        }
    }
    

    resources/applicationContext.xml

    <!-- UserService的创建权交给了Spring -->
    <bean id="userService" class="com.imooc.ioc.demo1.UserServiceImpl">
        <property name="name" value="李四"/>
    </bean>
    

    Bean的实例化三种方式

    resources/applicationContext.xml

    <!--Bean的实例化的三种方式============================-->
    <!--第一种:无参构造器的方式-->
    <bean id="bean1" class="com.imooc.ioc.demo2.Bean1"/>
    <!--第二种:静态工厂的方式-->
    <bean id="bean2" class="com.imooc.ioc.demo2.Bean2Factory" factory-method="createBean2"/>
    <!--第三种:实例工厂的方式-->
    <bean id="bean3Factory" class="com.imooc.ioc.demo2.Bean3Factory"/>
    <bean id="bean3" factory-bean="bean3Factory" factory-method="createBean3"/>
    

    1、采用无参数的构造方法的方式

    public class Bean1 {
        public Bean1(){
            System.out.println("Bean1被实例化了...");
        }
    }
    
    @Test
    public void demo1(){
        // 创建工厂
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 通过工厂获得类的实例:
        Bean1 bean1 = (Bean1)applicationContext.getBean("bean1");
    }
    

    2、静态工厂实例化方式

    public class Bean2 {
    
    }
    
    // Bean2的静态工厂
    public class Bean2Factory {
        public static Bean2 createBean2(){
            System.out.println("Bean2Factory的方法已经执行了...");
            return new Bean2();
        }
    }
    
    @Test
    public void demo2(){
        // 创建工厂
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 通过工厂获得类的实例:
        Bean2 bean2 = (Bean2)applicationContext.getBean("bean2");
    }
    

    3、实例工厂实例化

    public class Bean3 {
    
    }
    
    // Bean3的实例工厂
    public class Bean3Factory {
        public Bean3 createBean3(){
            System.out.println("Bean3Factory执行了...");
            return new Bean3();
        }
    }
    
    @Test
    public void demo3(){
        // 创建工厂
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 通过工厂获得类的实例:
        Bean3 bean3 = (Bean3)applicationContext.getBean("bean3");
    }
    

    Bean的常用配置

    1、一般情况下,装配一个Bean时,通过指定一个id属性作为Bean的名称,id属性在IOC容易中必须是唯一的,如果Bean的名称中含有特殊字符,就需要使用name属性
    2、class用于设置一个类的完全路径名称,主要作用是IOC容器生成类的实例
    Bean的作用域(scope属性):
    1、singleton(默认值)在SpringIOC容器中仅存在一个Bean实例,Bean以单实例的方式存在;
    2、prototype:每次调用getBean()时都会返回一个新的实例;
    3、request:每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境;
    4、session:同一个HTTP Session共享一个Bean,不同的HTTP Session使用不同的Bean。该作用域仅适用于WebApplicationContext环境

    Spring容器中Bean的生命周期

    Spring初始化bean或销毁bean时,有时需要做一些处理工作,因此Spring可以在创建和销毁bean的时候调用bean的两个生命周期方法

    <bean id="abc" class="com.imooc.hello"
    init-method="init"
    destory-method="destory"
    />
    

    当bean被载入到容器的时候调用init,当bean从容器中删除的时候调用destory(scope=singleton有效)

    Bean的生命周期的完整过程

    1. instantiate bean对象实例化
    2. populate properties 封装属性
    3. 如果Bean实现BeanNameAware执行setBeanName
    4. 如果Bean实现BeanFactoryAware或者ApplicationContextAware 设置工厂
      setBeanFactory或者上下文对象setApplicationContext
    5. 如果存在类实现BeanPostProcessor (后处理Bean) , 执行postProcessBeforeInitialization
    6. 如果Bean实现InitializingBean执行afterPropertiesSet
    7. 调用< bean init-method= "init">指定初始化方法init
    8. 如果存在类实现BeanPostProcessor (处理Bean),执行
      postProcessAfterInitialization
    9. 执行业务处理
    10. 如果Bean实现DisposableBean执行destroy
    11. s调用< bean destroy-method= "customerDestroy">指定销毁方法
      customerDestroy

    BeanPostProcessor的作用

    resources/applicationContext.xml

    <bean class="com.imooc.ioc.demo3.MyBeanPostProcessor"/>
    <bean id="userDao" class="com.imooc.ioc.demo3.UserDaoImpl"/>
    
    public class UserDaoImpl implements  UserDao {
        @Override
        public void findAll() {
            System.out.println("查询用户。。。");
        }
        @Override
        public void save() {
            System.out.println("保存用户。。。");
        }
        @Override
        public void update() {
            System.out.println("修改用户。。。");
        }
        @Override
        public void delete() {
            System.out.println("删除用户。。。");
        }
    }
    
    public class MyBeanPostProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            //System.out.println("第五步:初始化前方法...");
            return bean;
        }
        @Override
        public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
            //System.out.println("第八步:初始化后方法...");
            if ("userDao".equals(beanName)) {
                Object proxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if ("save".equals(method.getName())) {
                            System.out.println("权限校验===================");
                            return method.invoke(bean, args);
                        }
                        return method.invoke(bean, args);
                    }
                });
                return proxy;
            } else {
                return bean;
            }
        }
    }
    
    @Test
    public void demo2(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        Man man = (Man)applicationContext.getBean("man");
        man.run();
        applicationContext.close();
    }
    

    结果:

    image-20200616031401328

    1、第一个proxy是Proxy.newProxyInstance得到的实例。而第二个proxy是InvocationHandler中的invoke方法的参数名。
    2、这里的method属性传入的是Method类的对象,并不是一个名字。这个method对象是用真正的方法名,由方法名和形参抽象出Method对象。
    3、args[]中传入的是原方法执行所需要的参数,由于参数可能有多个,所以使用数组。
    4、这里不能返回this,invoke方法的返回值是代理类实例。this是当前对象的实例也就是InvocationHandler的实例。
    5、method.invoke(o, args)方法,用来执行对象o的目标方法。在课程中的例子实际上就是那个UserDaoImpl对象的save方法。method.invoke方法的返回值是原方法的返回值。method.invoke方法的作用实际和直接“对象.方法名”调用作用是相同的
    6、不能直接返回proxy对象。传入的参数proxy在我们重写的逻辑中没有直接用到,这只是父类中规定好的参数,我们重写时需要遵循。如果不return method.invoke就不会调用到想要调用的方法了。
    因为我们增强时返回的是Proxy.newProxyInstance的实例,即外面的proxy代理对象。将来我们要使用它来进行调用,代理在调用的时候会自动调用invoke从而达到增强效果。如果不使用method.invoke就不会调用到真正的类的方法了。
    如果同学还是不太理解,建议同学配合看一下后面的SpringAOP的 2-1 节JDK的动态代理课程
    

    Spring的属性注入

    对于类成员变量,注入方式有三种

    • 构造函数注入

    • 属性setter方法注入

    • 接口注入(不常用)

    Spring支持前两种

    构造方法注入

    通过构造方法注入Bean的属性值或依赖的对象,它保证了Bean实例在实例化后就可以使用
    构造器中注入在元素里声明的属性

    <constructor-arg name="name" valve="张三">
    

    set方法的属性注入

    使用set方法注入,在Spring配置文件中,通过设置注入属性

    第一种,value注入属性为普通类型的,如String,int型

    <property name="" value="">
    

    第二种,name为该类中的属性名,ref注入属性为对象的,值为其他bean的id或name

    <property name="" ref="">
    

    p名称空间的属性注入

    • 使用p命名空间

    • 为了简化XML文件配置,Spring从2.5开始引入一个新的p名称空间

    • 普通属性:p:属性名="xxx" 引入常量值

    • 属性为其他对象p:属性名-ref="xxx" 引用其它Bean对象

    需要在xml配置文件中引入新头部xmlns:p="http://www.springframework.org/shema/p"

    实例:

    <bean id="person" class="com.imooc.ioc.demo4.Person" p:name="大黄" p:age="34" p:cat-ref="cat"/>
    <bean id="cat" class="com.imooc.ioc.demo4.Cat" p:name="小黄"/>
    

    Spring的属性注入-SqEL注入

    (属性注入较为复杂时使用)

    可以在#{.}里面调用其它类里面对应的方法

    <property name="name" value="#{value}">
    <property name="name" value="#{‘张三’}"/>
    <property name="name" value="#{beanID.方法名()}">
    

    SpEL表达式语言

    语法:#{}

    #{'hello'} : 使用字符串
    #{beanId} : 使用另一个bean
    #{beanId.content.toUpperCase()} : 使用指定名属性,并使用方法
    #{T(java.lang.Math).PI} : 使用静态字段或方法
    

    复杂类型的属性注入

    <!--复杂类型的属性注入-->
    <bean id="collectionBean" class="com.i.ioc.demo5.CollectionBean">
    <!--数组类型-->
    <property name="arrs">
        <list>
            <value>aaa</value>
            <value>ccc</value>
            <value>bbb</value>
        </list>
    </property>
    <!--List集合类型属性注入-->
    <property name="list">
        <list>
            <value>111</value>
            <value>112</value>
            <value>113</value>
        </list>
    </property>
    <!--Set集合的属性注入-->
    <property name="set">
        <set>
            <value>ddd</value>
            <value>eee</value>
            <value>fff</value>
        </set>
    </property>
    <!--Map集合的属性注入-->
    <property name="map">
        <map>
            <entry key="aaa" value="123"></entry>
            <entry key="bbb" value="456"></entry>
            <entry key="ccc" value="789"></entry>
        </map>
    </property>
    <!--Properties的属性注入-->
    <property name="properties">
        <props>
            <prop key="username">root</prop>
            <prop key="password">1234</prop>
        </props>
    </property>
    </bean>
    
  • 相关阅读:
    Neptune w800开发版ubuntu linux环境编译通过——如何搭建开发环境
    neptune HarmonyOS开发板视频教程-环境搭建-编译-烧录-外设控制
    Neptune开发板与hiSpark开发板底板的管脚不兼容
    《设计心理学》要点(上)
    NLP(三十二):大规模向量相似度检索方案
    VIM编辑器设置
    (十一)pytorch加速训练的17种方法
    (十)pytorch多线程训练,DataLoader的num_works参数设置
    NLP(三十一):用transformers库的BertForSequenceClassification实现文本分类
    NLP(三十):BertForSequenceClassification:Kaggle的bert文本分类,基于transformers的BERT分类
  • 原文地址:https://www.cnblogs.com/greycdoer0/p/13192709.html
Copyright © 2020-2023  润新知