Spring学习笔记

一、Spring框架

1.1 Spring框架是什么

  • Spring是一种容器框架,用于配置各个组件(bean)并且维护各个组件bean之间的关系
  • Spring框架可以管理Web层,业务层,DAO层,持久层。
  • Spring提倡面向接口编程,配合DI技术可以实现层与层的解耦(主要是WEB层和业务层)
  • Spring框架图


    Spring学习笔记_第1张图片
    Spring架构.jpg

1.2 一个简单的spring项目

  • 目录结构

    • 引入spring的开发包(最小配置spring.jar以及日志包common-logging.jar)
    • 创建spring的一个核心文件ApplicationContext.xml, 该文件一般放在src目录下,该文件中引入xsd文件,可以自定义文件名。
      • hibernate核心文件 hibernate.cfg.xml
      • struts核心文件 struts-config.xml
      TestSpring
          |---src
              |---com.netease
              |          |---Service
              |                |---HelloService.java
              |                |---ByeService.java
              |          |---Test
              |                |---TestService.java
              |---ApplicationContext.xml
      External Libraries
          |--- spring.jar
          |--- common-logging.jar
          |--- ...
    
  • 代码详情

    package com.netease.Service;
    public class HelloService {
        private String name;
        private ByeService byeService;      /** 引用了一个ByeService*/
    
        public String getName() { return name;}
        public void setName(String name) { this.name = name;}
    
        public ByeService getByeService() { return byeService;}
        public void setByeService(ByeService byeService) { this.byeService = byeService;}
    
        public void sayHello() {
            System.out.println("hello "+name);
        }
    }
    
    package com.netease.Service;
    public class ByeService {
        private String name;
    
        public String getName() { return name;}
        public void setName(String name) {this.name = name;}
    
        public void sayBye() {
            System.out.println("Bye " + name);
        }
    }
    
    package com.netease.Test;
    import com.netease.Service.HelloService;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestService {
        public static void main(String[] args) {
            /*通过反射机制,在Spring容器中生成对象*/
            /*如果%%.xml放在某个包下,则就变为<包名+文件名>*/
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
            HelloService helloService = (HelloService) applicationContext.getBean("helloService");
            helloService.sayHello();
            helloService.getByeService().sayBye();
        }
    }
    
  • Spring核心容器文件ApplicationContext.xml

    • 在容器文件中配置Bean(Bean有可能是以下各种类型service/dao/domain/action/数据源)
    • Spring框架加载时,会阅读该容器文件,自动创建一个bean对象,并放入内存
    • 学习框架,最重要的就是学习各种配置
    
    
    
        
        
            
            
                Today
            
            
            
        
    
        
            
                Yesterday
            
        
    
    

1.3 Spring框架运行原理图

  • Spring框架什么时候被加载,Spring中配置的bean怎样被创建,Bean与Bean之间的关系如何维护

1.4 IOC与DI是什么

  • IOC(Inverse Of Controll ) 控制反转: 所谓控制反转就是把创建对象(bean),和维护对象(bean)的关系的权利从程序中转移到spring的容器(applicationContext.xml),而程序本身不再维护.
  • DI(Dependency Injection) 依赖注入: 实际上DI和IOC是同一个概念,Spring设计者认为DI更准确表示Spring核心技术

二、装配Bean

2.1 容纳Bean

  • ApplicationContext方式
    • ApplicationContext ac = new ClassPathXmlApplicationContext("com/netease/bean.xml")
    • 这句话执行时,不仅实例化了该容器,其中配置的所有scope为singleton的bean全部通过反射机制被实例化,scope为prototype的bean不会被实例化
    • 其他三种加载方式
      1. ClassPathXmlApplicationContext:从类路径中加载。
      2. FileSystemXmlApplicationContext:从文件系统加载,需要全路径
      3. XmlWebApplicationContext:从web系统中加载。
    • 好处:预先加载,速度快;缺点:耗内存
    • Bean的作用域,即scope


      Spring学习笔记_第2张图片
      scope.png
  • Bean工厂方式
    • BeanFactory factory = new XmlBeanFactory(new ClassPathResource("com/netease/bean.xml"))
    • 这句话执行时,仅实例化了该容器,容器中的bean不被实例化,只有当你使用factory.getBean("***")获取某个bean时,才实例化该bean对应的对象。类似于延迟实例化
    • 好处:节约内存;缺点:速度慢
  • 一般没有特殊要求,都采用ApplicationContext方式实例化(90%),移动端可采用Bean工厂方式

2.2 Bean生命周期

  • 完整生命周期步骤如下(通常只用到加粗的几步):

    1. 实例化:程序加载ApplicationContext文件,并把bean(scope=singleton)实例化到内存
    2. 设置属性:调用set方法设置bean中指定的属性
    3. 如果你实现了BeanNameAware接口, 则可以通过BeanName
    4. 如果你实现了BeanFactoryAware接口,则可以获取BeanFactory
    5. 如果你实现了ApplicationContextAware接口,则可以获取ApplicationContext
    6. 如果bean和一个后置处理器关联,则会自动去调用 postProcessBeforeInitialization()方法
    7. 如果你实现InitializingBean接口,则会调用afterPropertiesSet()方法
    8. 如果设置了,则可以在bean文件中定义自己的初始化方法init.
    9. 如果bean和一个后置处理器关联,则会自动去调用 postProcessAfterInitialization()方法
    10. 使用bean
    11. 容器关闭
    12. 可以通过实现DisposableBean接口来调用方法 destory,用来关闭资源等
    13. 可以在 调用定制的销毁方法destroy
  • ApplicationContext方式

    Spring学习笔记_第3张图片
    Context.png
  • Bean工厂方式

    Spring学习笔记_第4张图片
    Factory.png

2.3 装配Bean

2.3.1 什么是装配Bean

  • 告诉容器有哪些Bean以及容器如何使用依赖注入将它们配合在
    一起。

2.3.2 使用XML装配

  • 在XML文件中配置,spring会自动读取该文件加载配置好的Bean

2.3.3 添加一个Bean

  • 基本配置:一个bean ID + 全称类名

    
       
       
    
    
  • scope属性

    
      
      
    
    
    • 注意尽量使用默认的singleton,以防占用太大内存,影响程序性能
  • init-method 和destroy-method属性

    • 用途:在Spring实例化或者销毁bean时做一些处理工作
    • 使用方法:
      1. 声明方式:在XML文件中先声明该Bean拥有的初始化和销毁方法的函数名。在bean.java中实现initdestroy方法,函数名可自定义
         
        
      2. 标签方式:不需要在xml文件中声明初始化和销毁方法,在bean.java中采用标签方式声明初始化和销毁方法
        @PostConstruct
        public void ini(){…}
        @PreDestroy
        public void destroy(){…}
        
    • 其他进行初始化和销毁处理的方法:
      • Spring还提供了两个接口供bean.java使用,来进行实例化或者销毁时的处理,但不推荐

2.3.4 通过set方法注入属性和依赖

通过元素的子元素注入属性和依赖

  • 注入简单属性(基本类型和String)
    
          
                tom
          
    
    
  • 注入依赖
    • 引用其他的Bean
      
            
                  
            
      
      
      
      
    • 内部bean
      
        
              ...
        
      
      
  • 注入集合属性(数组,List,Set,Map)
    1. 设置null
      
             
      
      
    2. 数组
      
      
        
          小明
          李雷
          韩梅梅
        
      
      
    3. List
        
        
           
               
               
               
           
        
      
    4. Set
        
        
           
               
               
               
           
        
      
    5. Map
      
        
           
               
               
               
           
       
      
    6. property
      
        
            abcd
            hello
        
      
      
  • Bean的继承
    1. public class Student有name和age两个属性
    2. public class Gradate extends Student 有degree属性
    3. 在ApplicationContext文件中体现配置
      • 即student中配置过的属性graduate可以不配置
      • 如果配置,则会覆盖父类的属性
        
        
          
          
        
        
        
          
          
          
        
      

2.3.5 通过构造器注入依赖

通过元素的子元素注入属性


  
  
  

2.3.6 自动装配

不推荐使用,但需要了解

  • 通过autowire属性装配
  • 有四种自动装配类型:
    1. byName寻找和属性名相同的bean,若找不到,则装不上。(属性名和bean id名必须相同)
    2. byType:寻找和属性类型相同的bean,找不到,装不上,找到多个抛异常。
    3. constructor:查找和bean的构造参数一致的一个或多个bean,若找不到或找到多个,抛异常。按照参数的类型装配
    4. autodetect: (3)和(2)之间选一个方式。不确定性的处理与(3)和(2)一致。
    5. defualt : 这个需要在
    6. no : 不自动装配,这是autowrite的默认值。


      Spring学习笔记_第5张图片
      autowire.png
  • default说明
    • 需要在
      • 如果在指定了default-atuowrite后,所有的bean的默认的autowire就是中指定的装配方法;
      • 如果没有在指定defualt-autorwire,则默认是defualt-autorwire=”no”,所有的bean则默认不自动装配,除非自己配置autowire

2.3.7 通过标签自动装配(待跟进)

  • spring2.5提供了配置,即只需要在ApplicationContext.xml中写入这句话,可激活在类中探测到的各种注解,
  • 常用注解: @Required @Autowire @PostConstrct @PreDestroy @Resource @EJB @PersistenceContext @WebServiceRef
  • 非常有用

2.3.8 分散配置

通过在ApplicationContext.xml文件中配置context:property-placeholder 引入属性文件,有多个需要使用','号间隔.

  • 步骤如下:
    1. 配置属性文件db.property
       name=scott
       drivername=oracle:jdbc:driver:OracleDirver
       url=jdbc:oracle:thin:@127.0.0.1:1521:hsp
       pwd=tiger
      
    2. 在ApplicationContext.xml文件中引入db.properties文件,两种方式
      • 第一种

      • 第二种

        
            
                 
                 xx/yy/db.properties
                 xx/yy/db2.properties
                 
              
        
        
    3. 在ApplicationContext.xml文件中配置bean,采用占位符$方式
      
      
      
      
      
      
      

三、AOP原理剖析

Aspect Oriented Programming(AOP),即面向切面编程。对所有对象或一类对象编程。
在不增加代码的基础上,还增加新的功能

3.1 AOP原理

3.1.1 AOP术语介绍

  1. 切面(aspect):要实现的交叉功能,是系统模块化的一个切面或领域。如日志记录。
  2. 通知:切面的实际实现,他通知系统新的行为。如在日志通知包含了实现日志功能的代码,如向日志文件写日志。通知在连接点插入到应用系统中。
  3. 连接点:应用程序执行过程中插入切面的地点,可以是方法调用,异常抛出,或者要修改的字段。
  4. 切入点:定义了通知应该应用在哪些连接点,通知可以应用到AOP框架支持的任何连接点。
  5. 引入:为类添加新方法和属性。
  6. 目标对象:被通知的对象。既可以是你编写的类也可以是第三方类。
  7. 代理对象:将通知应用到目标对象后创建的对象,应用系统的其他部分不用为了支持代理对象而改变。
  8. 织入:将切面应用到目标对象从而创建一个新代理对象的过程。织入发生在目标对象生命周期的多个点上:
    • 编译期:切面在目标对象编译时织入,这需要一个特殊的编译器。
    • 类装载期:切面在目标对象被载入JVM时织入,这需要一个特殊的类载入器。
    • 运行期:切面在应用系统运行时织入。

3.1.2 AOP原理图

Spring学习笔记_第6张图片
aop原理图.png

原理解释

  • 代理对象:仅需要配置在XML配置文件中即可,用于将目标对象和通知进行绑定;
  • 通知:切面编程的实现,只要在代理对象中配置了目标对象,该通知就可以作用到目标对象上;
  • 目标对象:需要使用通知的对象,例如想要通过通知来写日志,做安全检查等

通知类型

Spring学习笔记_第7张图片
通知类型.png

3.1.3 举个栗子

本例中,

  • 有两个接口HelloServiceInterfaceByeServiceInterface,其中类SayingService实现了这两个接口中的方法。
  • 配置文件中,为类SayingService的具体对象配置了四种通知(严格说是五种),分别在该对象调用每一个方法时为其执行这几个通知
  • 注意!!!通知针对的是对象,对象调用几个方法,通知就会执行多少遍,除非配置切入点,使得通知绑定到具体的方法上;
  • 其他解释见代码注释
  • 目录结构
      TestSpring
          |---src
              |---com.netease
              |          |---Advice
              |                |---MyBeforeAdvice (前置通知,实现了接口MethodBeforeAdvice)
              |                |---MyAfterReturningAdvice (后置通知,实现了接口AfterReturningAdvice)
              |                |---MyInterceptAdvice (环绕通知,实现了接口MethodInterceptor)
              |                |---MyThrowableAdvice (异常通知,实现了接口ThrowsAdvice)
              |          |---Service
              |                |---ByeServiceInterface.java (包含方法sayBye)
              |                |---HelloServiceInterface.java (包含方法sayHello)
              |                |---SayingService.java (实现了以上两个接口)
              |          |---Test
              |                |---TestService.java
              |---ApplicationContext.xml
      External Libraries
          |--- spring.jar
          |--- common-logging.jar
          |--- ...
    
  • 代码描述
    public class TestService {
        public static void main(String[] args) {
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
            /*注意这里必须获取代理对象!!否则就白配置了*/
            /*得到的对象为什么可以是HelloServiceInterface --> 这里可以理解为,代理类实际上实现了这个接口,因此可以通过强转得到*/
            HelloServiceInterface helloService = (HelloServiceInterface) applicationContext.getBean("proxyFactoryBean");
            helloService.sayHello();
            /*同理,由于代理类同样实现了ByeServiceInterface接口*/
            ByeServiceInterface byeService = (ByeServiceInterface) helloService;
            byeService.sayBye();
        }
    }
    
  • 配置文件
    
    
    
        
        
        
        
        
    
        
        
        
            
            
        
    
    
        
        
            
                zhujie
            
        
    
        
        
            
            
                
                    com.netease.Service.HelloServiceInterface
                    com.netease.Service.ByeServiceInteface
                
            
            
            
                
                    
                    
                    nameMatchMethodPointcutAdvisor
                    myBeforeAdvice
                    myAfterReturningAdvice
                    myInterceptAdvice
                    myThrowableAdvice
                
            
            
            
            
        
    
    

你可能感兴趣的:(Spring学习笔记)