Spring基础篇(1)——Spring框架核心介绍

DI(Dependency Injection),依赖注入

和咱们常据说的另外一个概念IOC(控制反转)其实归根结底实现的功能是相同的,只是一样的功能站在不一样的角度来阐述罢了。咱们须要知道的是,什么叫依赖注入,为何要依赖注入。搞清这两点,我想对Spring的学习在思想上就算是上道了。php

在没用使用Spring的时候——也就是没有依赖注入的时候,java应用程序的类与类之间要实现相互的功能协做是比较费劲的,某个类(A)要实现它的功能若是须要依赖另外一个类(B)的协做的话,就须要在A类中主动建立出B类的对象,才能使用B类的方法完成功能(这里看官就不要去纠结静态方法之类的状况了)。这等因而A类须要负责B类对象整个生命周期的管理。在极度简单的状况下,在一个类中new出另外一个类的对象彷佛并无什么问题,可是复杂的应用程序类与类的协做关系每每是多边的,咱们并不知道一个类功能的实现会依赖多少个另类对象来协做,因此在类中自行建立对象而且管理对象的整个生命周期,会形成代码的高度耦合以及不可想象的复杂度。那么,试想,若是咱们能将对象的生命周期交给第三方组件来管理,当某个类须要另外的对象时第三方组件就直接建立出来交给它,这样,类就能够只专一于本身功能的实现,而不用去管理其余类对象的生命周期,这样类的功能就单纯了不少。java

是的,你必定已经明白了,Spring(容器)就是这个第三方组件。咱们只须要告诉Spring(容器)有哪些对象须要管理就好了,不用去关心Spring框架是如何建立对象的。这样,当某个类A须要类B对象时,若是类B已经声明交给了Sping容器管理,那么在程序运行到类A须要类B时,Spring容器就经过依赖注入的方式,将类B对象注入到类A中协助完成业务功能。经过第三方组件的依赖注入,对象无需再自行的建立和管理类与类之间的依赖关系了。对象的建立依赖注入的方式也有多种,譬如接口注入,构造方法注入,setter方法注入等等。说到这里,你对依赖注入应该有比较直白的认知了。至于为何要依赖注入,上文已经说得很明白了,就是为了减小代码中组件之间的耦合度,咱们仍是先经过简单示例来直观感觉下依赖注入比本身管理对象的好处吧——spring

public class Man implements Human {
    private QQCar car;
    public Man() {
        this.car = new QQCar();
    }
    @Override
    public void xiabibi() {
    }
    public void driveCar(){
        car.drive();
    }
}
复制代码

接口Car暂有两个实现:奔驰车和QQ车,在以上Man类和QQCar类高度耦合的代码中,老司机经过构造器只建立了QQ车对象,因此只能开QQ车,那么老司机想开奔驰怎么办呢,你让他从新建立奔驰车的对象吗?这样高度耦合的代码彷佛是毫无办法的,那么,咱们经过注入对象的方式对上述代码作一番改进:数据库

public class Man implements Human {
    private Car car;
    public Man(Car car) {
        this.car = car;
    }
    @Override
    public void xiabibi() {
    }

    public void driveCar() {
        car.drive();
    }
}
复制代码

以上代码根据多态特性,经过构造器接口注入的方式屏蔽掉了具体的对象实现,这样,老司机就能想开什么车就开什么车了。这就是依赖注入带来的好处。 express

IoC:Inverse of Control(控制反转)

  • 读做 “反转控制”,更好理解,不是什么技术,而是一种设计思想,就是将本来在程序中手动建立对象的控制权,交由Spring框架来管理。
  • 正控:若要使用某个对象,须要本身去负责对象的建立
  • 反控:若要使用某个对象,只须要从 Spring 容器中获取须要使用的对象,不关心对象的建立过程,也就是把建立对象的控制权反转给了Spring框架
  • 好莱坞法则: Don’t call me ,I’ll call you

一个例子

控制反转显然是一个抽象的概念,咱们举一个鲜明的例子来讲明。在现实生活中,人们要用到同样东西的时候,第一反应就是去找到这件东西,好比想喝新鲜橙汁,在没有饮品店的日子里,最直观的作法就是:买果汁机、买橙子,而后准备开水。值得注意的是:这些都是你本身“主动”创造的过程,也就是说一杯橙汁须要你本身创造。编程

然而到了今时今日,因为饮品店的盛行,当咱们想喝橙汁时,第一想法就转换成了找到饮品店的联系方式,经过电话等渠道描述你的须要、地址、联系方式等,下订单等待,过一下子就会有人送来橙汁了。app

请注意你并无“主动”去创造橙汁,橙汁是由饮品店创造的,而不是你,然而也彻底达到了你的要求,甚至比你创造的要好上那么一些。框架

Spring IoC 阐述

这就是一种控制反转的理念,上述的例子已经很好的说明了问题,咱们再来描述一下控制反转的概念:控制反转是一种经过描述(在 Java 中能够是 XML 或者注解)并经过第三方(Spring)去产生或获取特定对象的方式。ide

  • 好处:下降对象之间的耦合,咱们不须要理解一个类的具体实现,只须要知道它有什么用就行了(直接向 IoC 容器拿)

主动建立的模式中,责任归于开发者,而在被动的模式下,责任归于 IoC 容器,基于这样的被动形式,咱们就说对象被控制反转了。(也能够说是反转了控制)性能

Spring IoC 和 依赖注入的例子(经过 xml 文件配置的方式装配 bean)

  1. 新建一个空的 Java 项目,命名为【spring】
  2. 新建一个名为【lib】的目录,并添加进必要的 jar 包,导入项目

  1. 在 Packge【pojo】下新建一个【Source】类:
package pojo;

public class Source {  
    private String fruit;
    private String sugar;
    private String size;
}
复制代码
  1. Packge【pojo】下新建一个【JuiceMaker】类:
package pojo;

public class JuiceMaker {

    // 惟一关联了一个 Source 对象
    private Source source = null;

    public String makeJuice(){
        String juice = "xxx用户点了一杯" + source.getFruit() + source.getSugar() + source.getSize();
        return juice;
    }
}
复制代码
  1. 在 xml 文件中配置 JuiceMaker 对象:
  • 注意:这里要使用 ref 来注入另外一个对象
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="source" class="pojo.Source">
        <property name="fruit" value="橙子"/>
        <property name="sugar" value="多糖"/>
        <property name="size" value="超大杯"/>
    </bean>
    <bean name="juickMaker" class="pojo.JuiceMaker">
        <property name="source" ref="source" />
    </bean>
</beans>
复制代码
  1. 在 Packge【test】下新建一个【TestSpring】类:
package test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.JuiceMaker;
import pojo.Source;

public class TestSpring {

    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext(
                new String[]{"applicationContext.xml"}
        );

        Source source = (Source) context.getBean("source");
        System.out.println(source.getFruit());
        System.out.println(source.getSugar());
        System.out.println(source.getSize());

        JuiceMaker juiceMaker = (JuiceMaker) context.getBean("juickMaker");
        System.out.println(juiceMaker.makeJuice());
    }
}
复制代码
  1. 运行测试代码:

总结: IoC 和 DI 实际上是同一个概念的不一样角度描述,DI 相对 IoC 而言,明确描述了“被注入对象依赖 IoC 容器配置依赖对象”

AOP(Aspect Oriented Programming),面向切面编程。

若是说 IoC 是 Spring 的核心,那么面向切面编程就是 Spring 最为重要的功能之一了,在数据库事务中切面编程被普遍使用。

AOP 即 Aspect Oriented Program 面向切面编程

首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能。

  • 所谓的核心业务,好比登录,增长数据,删除数据都叫核心业务
  • 所谓的周边功能,好比性能统计,日志,事务管理等等

周边功能在 Spring 的面向切面编程AOP思想里,即被定义为切面

在面向切面编程AOP的思想里面,核心业务功能和切面功能分别独立进行开发,而后把切面功能和核心业务功能 "编织" 在一块儿,这就叫AOP

AOP 的目的

AOP可以将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减小系统的重复代码,下降模块间的耦合度,并有利于将来的可拓展性和可维护性。

AOP 当中的概念:

  • 切入点(Pointcut) 在哪些类,哪些方法上切入(where)
  • 通知(Advice) 在方法执行的什么实际(when:方法前/方法后/方法先后)作什么(what:加强的功能)
  • 切面(Aspect) 切面 = 切入点 + 通知,通俗点就是:在什么时机,什么地方,作什么加强!
  • 织入(Weaving) 把切面加入到对象,并建立出代理对象的过程。(由 Spring 来完成)

AOP 编程

  1. 在 Packge【service】下建立 【ProductService】类:
package service;

public class ProductService {
    public void doSomeService(){
        System.out.println("doSomeService");
    }
}
复制代码
  1. 在 xml 文件中装配该 bean:
<bean name="productService" class="service.ProductService" />
复制代码
  1. 在【TestSpring】中编写测试代码,运行:

  1. 在 Packge【aspect】下准备日志切面 【LoggerAspect】类:
package aspect;

import org.aspectj.lang.ProceedingJoinPoint;

public class LoggerAspect {
    
    public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("start log:" + joinPoint.getSignature().getName());
        Object object = joinPoint.proceed();
        System.out.println("end log:" + joinPoint.getSignature().getName());
        return object;
    }
}
复制代码
  1. 在 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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <bean name="productService" class="service.ProductService" />
    <bean id="loggerAspect" class="aspect.LoggerAspect"/>

    <!-- 配置AOP -->
    <aop:config>
        <!-- where:在哪些地方(包.类.方法)作增长 -->
        <aop:pointcut id="loggerCutpoint" expression="execution(* service.ProductService.*(..)) "/>

        <!-- what:作什么加强 -->
        <aop:aspect id="logAspect" ref="loggerAspect">
            <!-- when:在什么时机(方法前/后/先后) -->
            <aop:around pointcut-ref="loggerCutpoint" method="log"/>
        </aop:aspect>
    </aop:config>
</beans>
复制代码
  1. 再次运行 TestSpring 中的测试代码,代码并无改变,可是在业务方法运行以前和运行以后,都分别输出了日志信息:

相关文章
相关标签/搜索