美文网首页
Spring之旅(一):初识Spring

Spring之旅(一):初识Spring

作者: xuweizhen | 来源:发表于2018-06-06 12:06 被阅读0次

Spring之旅

一.Spring根本使命

简化java开发

1. 简化开发策略

  1. 基于POJO的轻量级和最小侵入性编程(需要理解)
  2. 通过依赖注入和面向接口实现松耦合(需要理解)
  3. 基于切面和惯例进行声明式编程(需要理解)
  4. 通过切面和模板减少样板式代码(需要理解)

2. 策略1:基于POJO的轻量级和最小侵入性编程

javaBean使用POJO而不需要继承或实现框架中的接口,就能实现Spring框架的功能。

框架和应用代码之间松耦合。

侵入性: 很多框架需要在应用代码中继承或实现框架的接口,让应用与框架绑定。

实现非侵入性的方式:

  1. 依赖注入

3. 依赖注入

3.1 概念

对象中可能需要其他的依赖对象,在依赖注入中对象不需要自己创建依赖的对象,而是依赖的对象将依赖关系自动交给对象。

3.2 依赖注入方式

(1) 构造器注入

在javaBean的构造函数中,将所依赖的类传进来。这样所依赖的对象主动交给javaBean,完成javaBean对象的创建。

扩展: 构造函数中传入来的依赖,最好是接口。这样所有实现接口的类都可以注入进来,屏蔽了类的具体实现。

3.3 问题

构造器注入在创建javaBean对象时,需要传依赖的对象,这个依赖的对象如何来?

如果是依赖的对象是接口,传哪一个实现类?

3.4 装配

(1) 概念

创建组件之间的协作行为

即配置javaBean和依赖的类。

(2) Spring装配方式

Spring有多重装配方式,常见的有两种:xml文件和java

:javaBean:Foo (接口)依赖javaBean:Bar (接口)

FooImp实现了Foo接口,BarImp实现了Bar接口。

(2.1) xml文件
<bean id="foo" class="com.spring.FooImp">
    <constructor-arg ref="bar">
</bean>

<bean id="bar" class="com.spring.BarImp"/>
(2.2) java配置
@configuration
public class FooConfig{
    
    @Bean
    public Foo foo(){
        return new FooImp(bar())
    }
    
    @Bean
    public Bar bar(){
        return new BarImp();
    }
}

装配好后的组件如何运行起来的呢?

Spring 通过应用上下文(Application Context)装载Bean的定义并把它们组装起来。

Spring的Application Context全权负责对象的创建与组装。

Spring 有多种实现Application Context的方式,主要区别在于如何加载配置。

完整例子:
  • Food接口
public interface Food {
    
    String foodName();
}
  • Apple类
public class Apple implements Food{

    public String foodName() {
        String foodname = "红富士苹果";
        System.out.println("这是非常好的" + foodname);
        return foodname;
    }   
}
  • Animal接口
public interface Animal {
    
    void eat();
}
  • Dog类
public class Dog implements Animal{
    
    private Food food;

    public Dog(Food food) {
        this.food = food;
    }

    public void eat() {
        System.out.println("dog like" + this.food.foodName());  
    }
    
}
  • AnimalConfig配置
@Configuration
public class AnimalConfig {

    @Bean
    public Animal animal(){
        return new Dog(food());
    }
    
    @Bean
    public Food food(){
        return new Apple();
    }
}

  • main方法中加载注解配置上下文,并获取Bean类
public class Demo {
    
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AnimalConfig.class);
        
        Animal animal = context.getBean(Animal.class);
        animal.eat();
    }
}
  • 打印结果输出:
这是非常好的红富士苹果
dog like红富士苹果

DI可以让各组件松耦合,而AOP可以把散落在系统各处的同类功能分离出来形成通用组件,接下来,让我们了解下AOP

AOP

AOP是啥?

AOP是面向切面编程,aspect-oriented programming.

可以将多个系统都调用的服务,抽离成单独的组件,以消除这些服务散落在系统各处带来的复杂性。

为何要使用AOP?

如果不使用AOP,散落在系统各处的同类功能代码,不仅不利于管理,而且会非常混乱。

如日志服务和安全管理,系统很多业务都需要调用它们的服务。想想看:

  • 如果日志服务有改动,所有的业务都需要同时改动。就算抽离成一个通用方法,方法的调用也会出现在各处,不利于维护与管理。
  • 而且这些服务又不是核心的业务代码,不应该在核心业务代码中去码这些东西,代码会非常混乱。

AOP的好处在哪里?

AOP能够让这些服务模块化,以声明的方式去应用到需要这些服务的影响的组件中。

这些组件更关注自身的核心业务而不需要关注其他服务。

总之,AOP能让POJO变得简单。

如何理解AOP?

AOP可以想象成包裹核心业务组件的一层外壳,以声明的方式灵活的运用到业务组件中,甚至核心业务层都不知道它们的存在,将核心业务与日志事物等服务功能分离。

例子:

在每个animal eat food之前,都会有doctor过来给animal检查,eat food之后,又会给animal称重。

你可能会想到:在每个eat方法的开头添加检查cheak方法,在结尾添加称重weight方法。

但是仔细想想,animal 中需要管理 doctor的方法?check和weight不是animal的核心业务呀,这些都让doctor自己做就好了。

如果想要管理也OK,你给我将doctor的实例传给我,依赖注入进来。但如果doctor为空呢?

简单的事情就变得很复杂,倒不如是doctor的方法就由doctor自己来管理。

利用AOP,可以让animal在eat food之前必须check,而animal一无所知。

详细代码:

Doctor类
public class Doctor implements Person{
    
    public void check() {
        System.out.println("医生来检查啦");       
    }

    public void weight() {
        System.out.println("吃胖啦!");     
    }

}
配置AOP的xml文件
<bean id="food" class="com.example.beans.Apple"/>
    
    <bean id="animal" class="com.example.beans.Dog">
        <constructor-arg ref="food"/>
    </bean>
    
    <bean id="person" class="com.example.beans.Doctor"/>
    
    <aop:config>
        <aop:aspect ref="person">
            <aop:pointcut expression="execution(void com.example.beans.Dog.eat(..))" id="doctorSay" />
            <aop:before method="check" pointcut-ref="doctorSay" />
            <aop:after method="weight" pointcut-ref="doctorSay" />
        </aop:aspect>
    </aop:config>
输出日志:
医生来检查啦
这是非常好的红富士苹果
dog eat 红富士苹果
吃胖啦!

从这个例子我们可以了解到

  • 没有任何代码说明Doctor是一个切面,它依然是一个POJO。
  • 没有任何代码说明Dog eat调用了Doctor的方法,但Doctor的方法依然在Dog eat方法执行时启用了。
  • Doctor依然是POJO,也就意味着它可以使用DI等其他POJO可以做的事。

使用模板Template消除样板式代码

每次在码东西的时候,经常碰到这些东西是不是在哪见过。没错,你可能真的在重复的码同一个东西,这就是样板式的代码。

最直接的例子就是java创建jdbc的连接,执行sql,再放入Bean类中,最后释放连接,抛出异常。

其中创建jdbc和释放连接抛出异常都是通用的写法,样板式的代码,但又不得不写。其实真正的业务只有执行SQL,并将查询结果放入Bean类中。

使用模板可以消除这些样式代码,可以理解成将这些样式代码封装成了一个模板类,只需码真正的核心业务就行了。

相关文章

网友评论

      本文标题:Spring之旅(一):初识Spring

      本文链接:https://www.haomeiwen.com/subject/xblbsftx.html