• Spring学习笔记-Spring之旅-01


    使用Spring简化JAVA开发

    Spring的四种关键策略:

      ●基于POJO的轻量级和最小侵入式编程;

      ●通过依赖注入(DI)和面向接口实现松耦合;

      ●基于切面(AOP)和惯例进行声明式编程。

      ●通过切面和模板减少样板式代码。

    几乎Spring所做的任何事都可以追溯到上面的一条或多条策略。

    依赖注入(DI)

     传统编程经常需要多个对象相互协作完成某个功能,每个对象管理与自己相互协作的对象。

    传统开发常见的例子

    比如下面的例子

    一个Amercan类,其中有一个sayHello方法。

    一个DoSomething类,调用American类执行sayHello方法。

    public class  American{
         public void sayHello(){
             System.out.println("American say hello");
         }          
     }
    public class DoSomething{
        private American american;  //声明一个American类
        DoSomething(){
            this.american=new American();  //构造函数中初始化American类变量,这里与其紧耦合
        }
        public void do() {
            person.sayHello();
        }
    }
    public class Test {
        public static void main(String[] args){
            DoSomething doSomething=new DoSomething();
            doSomething.sayHello();
        }
    }

    可以发现在DoSomething类的构造函数自行创建了American类,与其紧密耦合在了一起,后期扩展、测试会面临很大困难。

    改善后的例子:

    public interface Person{
         public void sayHello();  
     }
    public class  American implements{
         public void sayHello(){
             System.out.println("American say hello");
         }          
     }
    public class DoSomething{
        private Person person;  //声明一个Person接口
        DoSomething(Person person){
            this.person=person;  //person通过构造参数传入
        }
        public void do() {
            person.sayHello();
        }
    }
    public class Test {
        public static void main(String[] args){
            DoSomething doSomething=new DoSomething(new American);  //在构造函数中传入Perison实现
            doSomething.sayHello();
        }
    }

    现在使声明一个Person接口,在DoSomething声明一个Person接口,将Person接口的实例通过构造器参数传入,没有与任何实现产生耦合,只要实现了Person接口的类都能sayHello。

    使用Spring装配bean和注入

    Spring有多中装配bean的方式,以下为2种常用的方式:

      ●XMl

      ●注解

     以下以XML为例子说明

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"  
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
            xmlns:aop="http://www.springframework.org/schema/aop"  
            xmlns:tx="http://www.springframework.org/schema/tx"  
            xmlns:context="http://www.springframework.org/schema/context"  
            xsi:schemaLocation="  
                http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
                http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd  
                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
            > 
        <bean id="doSomething" class="com.xyd.demo1.DoSomething">
            <constructor-arg ref="person"/>    <!-- 注入American -->
        </bean>
        
        <bean id="person" class="com.xyd.demo1.American"><!-- American类  -->
        </bean>
    </beans>

    以上xml声明了2个bean,一个DoSomething类,同时构造参数传入了American bean的引用。一个American类。

    下面修改测试代码

        public static void main(String[] args) {
            //DoSomething doSomething=new DoSomething(new American());
            //doSomething.doing();
            ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("SayHello.xml");
            DoSomething doSomething=context.getBean(DoSomething.class);
            doSomething.doing();
        }

    使用XML应用上下文装载配置文件,然后使用getBean获得DoSomething类的实例,然后直接调用其doing()方法,输出American say hello!

    四月 07, 2018 10:48:13 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
    信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@506c589e: startup date [Sat Apr 07 22:48:13 CST 2018]; root of context hierarchy
    四月 07, 2018 10:48:13 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
    信息: Loading XML bean definitions from class path resource [SayHello.xml]
    American say hello!

    XML应用上下文获得了bean配置文件,得到DoSomething的引用后只需要简单的调用doing()就可以了,这个类完全不知道传入的是哪个Person接口的实例,只有配置文件中知道哪个实例被传入。

    应用切面(AOP)

    DI能然相互协作的软件保持松耦合,面向切面(AOP)允许把遍布应用各处的功能 分离出来形成可重用的组件。如需要在调用sayHello记录一下日志等等,通常称为横切关注点,借助AOP可以使这些服务模块化。

    还是以上述例子,但是要增加一个功能,比如美国人说hello之前进行询问,之后给一个回应。

    public class Reply {
        public void sayHelloBefor(){    //sayHello前调用
            System.out.println("say hello please!");
        }
        public void sayHelloAfter(){    //sayHello之后调用
            System.out.println("really good");
        }
    }

    传统的的做法是下面这样

    public class DoSomething {
        Person person;
        Reply reply=new Reply();
        public DoSomething(Person person){
            this.person=person;
        }
        public void doing(){
            reply.sayHelloBefor();    //DoSomething应该管理它吗?
            person.sayHello();
            reply.sayHelloAfter();
        }
    }

    程序正常输出了

    say hello please!
    American say hello!
    really good

    但是这简单的代码变的复杂,如果还需要没有人进行回应的场景那会变得更复杂,而利用AOP可以声明在sayHello前必须进行请求和询问,而DoSomething本身不需要访问Reply的代码,下面修改配置文件。

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"  
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
            xmlns:aop="http://www.springframework.org/schema/aop"  
            xmlns:tx="http://www.springframework.org/schema/tx"  
            xmlns:context="http://www.springframework.org/schema/context"  
            xsi:schemaLocation="  
                http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
                http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd  
                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
            > 
        <bean id="doSomething" class="com.xyd.demo1.DoSomething">    
            <constructor-arg ref="person"/>    <!-- 注入American -->
        </bean>
        
        <bean id="person" class="com.xyd.demo1.American"> <!-- American类  -->
        </bean>
        
        <bean id="reply" class="com.xyd.demo1.Reply">    <!-- Reply类  -->
        </bean>
        
        <aop:config>
            <aop:aspect ref="reply">    <!-- 引用reply bean  -->
                <aop:pointcut id="sayHello"  expression="execution(* *.doing(..))" /> <!-- 定义切点( AspectJ切点表达式 )-->
                
                <aop:before method="sayHelloBefor" pointcut-ref="sayHello"/>    <!-- 声明前置通知 -->
                
                <aop:after method="sayHelloAfter"  pointcut-ref="sayHello"/>        <!-- 声明后置通知 -->
            </aop:aspect>
        </aop:config>
    </beans>

    接下来运行一下程序,输出如下结果。

    say hello please!
    American say hello!
    really good

    AOP所做的事情,就是通过少量的配置,就可以吧Reply声明为一个切面,Reply仍然是一个POJO,不需要改变现有代码。

    Bean容器

    在Spring的应用中,应用对象生存于Spring容器中,容器负责创建、装配它们,配置并且管理对象的整个声明周期。容器是Spring框架的核心,使用DI管理构成应用的组件,会创建相互协作的组件之间的关联。

    Spring中容器并不只有一个,其自带了多个容器实现,可归类为两种不同类型:

      ● bean工厂(由org.springframework.beans.factory.eanFactory接口定义,最简单,提供基本的DI支持)

      ● 应用上下文(由org.springframework.context.applicationContext接口定义,基于BeanFactory构建,提供应用框架级别的服务,例如从属性解析文本以及发布应用实践给感兴趣的事件监听者)

     常用的容器类型为应用上下文,经常遇到的应用上下文:

      ● AnnotationConfigApplicationContext:从一个或多个基于Java的配置类中加载Spring上下文;

      ● AnnotationConfigApplicationContextAnnotationConfigWebApplicationContext:从一个或多个基于Java的配置类中加载Spring Web的应用上下文

      ● ClassPathXmlApplicationContext:从类路径下的一个或多个XML配置文件中加载上下文定义,把应用上下文的定义文件作为类资源。

      ● FileSystemXmlapplictioncontext:从文件系统下的一个或多个XML配置文件中加载上下文定义。

      ● XMLWebApplicationContext:从Web应用下的一个或多个XMl配置文件中加载上下文定义。

    无论使用何种类型的应用上下文,将bean加载到bean工厂的过程都是相似的。

    下面的代码加载一个xml配置文件的应用上下文:

    ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("SayHello.xml");

    获得应用上下文之后,就可以调用上下文的getBean()方法获得bean。

    bean的生命周期

    1、对bean进行实例化,new;

    2、将值和bean的引用注入到bean对应的属性中 ;

    3、如果bean实现了BeanNameAware接口,则将bean的ID传递给setBean-Name()方法;

    4、如果bean实现了BeanFactoryAware接口,则调用setBeanFactory()方法,将BeanFactory容器实例传入;

    5、如果bean实现了ApplicationContextAware接口,则将调用setApplicationContext()方法,将bean所在的应用上下文的引用传进来;

    6、如果bean实现了BeanPostProcessor接口,则将调用它们的post-ProcessBeforeInitialization()方法;

    7、如果bean实现了InitializeingBean接口,则将调用它们的after-PropertiesSet()方法,类似如果bean使用init-method声明了初始化方法,此方法也会调用。

    8、如果bean实现了BeanPostProcessor,则将调用它们的post-ProcessAfterInitialization()方法;

    9、此时bean已经准备就绪,可以被应用使用,它们将一直驻留在应用上下文中,直到上下文被销毁;

    10、如果bean实现了DisposableBean接口,将调用它的destroy()接口方法,同样,如果bean使用destroy-method声明了销毁方法,该方法也会被调用;

  • 相关阅读:
    linux 和unix 的区别
    Ubuntu 12.04下安装ibus中文输入法
    安装vmware tools失败解决方法
    snort简介以及在Ubuntu下的安装
    ubuntu下tcpdump使用
    securecrt在linux与windows之间传输文件(转)
    大数据处理时用到maven的repository
    Spark之命令
    Spark之集群搭建
    Spark之scala
  • 原文地址:https://www.cnblogs.com/vice/p/8712132.html
Copyright © 2020-2023  润新知