Spring实战(一)-DI和AOP入门

前言

作为一个Java开发者,对Spring不可谓不熟悉。但从来没有系统的对他进行过学习,都是建立在项目开发的基础上对他进行一些使用。现在抽出一些时间从头开始学习Spring,便于更好的梳理整个框架的结构,对今后学习SpringBoot和SpringCloud打下良好的基础。

Spring简介

Spring是一个开源框架,它的最根本的使命就是简化Java开发。为了降低Java开发的发杂性,Spring采取了以下四种关键策略:
1. 基于POJO的轻量级和最小入侵性编程
2. 通过依赖注入和面向接口实现松耦合
3. 基于切面和惯例进行声明式编程
4. 通过切面和模板减少样板式代码

1.如何基于POJO的最小入侵性编程(DI)

实际上,Java开发中很多框架的使用都是通过强迫应用继承它们的类或者实现它们的接口从而导致应用与框架绑死,一个典型的例子就是EJB2时代的无状态会话bean。而在基于Spring构建的应用中,通常没有任何痕迹表明你使用了Spring,最不济一个类或许会使用Spring注解,但它依旧是POJO类。

举个简单的例子:

public class HelloWorldBean{
    public String sayHello(){
        return "Hello World";
    }
}

这是一个普通的Java类(POJO),没有任何地方表明它是一个Spring组件。虽然是个简单的POJO,但Spring可通过DI(依赖注入)来装配它,来使各个应用对象之间松耦合。

那么DI(依赖注入)又是如何实现的呢?

在我们的实际应用当中,都会由多个类组成,并且这些类相互之间进行写作来完成特定的业务逻辑,现在举个例子看看传统的做法:
在传统的三层架构中,我们经常会这么使用

public class UserDAOImpl implements UserDAO{
    @Override
    public User findByName(String name){
        return  null;
    }
}

public class UserServiceImpl implements UserService{
    private UserDAO userDAO = new UserDAOImpl();
    @Override
    public User findUser(String name){
        return userDAO.findByName(name);
    }
}

当然,我们可能不会直接new UserDAOImpl(),而是通过一个工厂方法来获取这个对象,但是不管是前者还是后者,UserDAO的对象都是在UserService中进行创建的,即它的控制权掌握在另一个类中。在这样的情况下,它们具有较高的耦合度,如果我们修改了UserDAO的实现类,那么也要在对应耦合的类中进行一定的修改。
在这样的情况下,对于对象的管理和维护就会变得不友好,那么我们能不能实现在我们需要的时候自动创建对象呢?这就要用到SpringDI(依赖注入)了,在我们需要创建对象的时候,通知Spring容器,它就会把这个对象传递到需要的地方。

在spring中,BeanFactory就是这样一个容器,我们只需将我们的Bean配置到BeanFactory的配置文件中,就能够进行统一的管理,如下 spring.xml

<bean id="userDAO" class="com.example.DAO.impl.UserDAOImpl"/>

也可以在配置中告诉Spring你需要什么样的对象:

<bean id="userService" class="com.example.service.impl.UserService.Impl">
    <!-- userDAO属性需要提供setter -->
    <property name="userDAO" ref="userDAO"/>
</bean>

这样,整个对象的管理就都交给Spring进行统一的管理,当需要修改某个类型对象的实现的时候,只需要修改这个配置文件,而不需要对代码进行修改了。

Spring通过ApplicationContext装载bean的定义并把它们组装起来,因为上述使用的是xml配置方式,因而使用ClassPathXmlApplicationContext来加载配置。

使用方式如下:

@Test
public void test(){
     // 基于spring.xml文件创建了Spring应用上下文
     ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:spring.xml");
     // 根据上下文对象获得一个 id 为userService的bean
     UserService userService = ctx.getBean("userService", UserService.class);
     User user = userService.findUser("admin");
     assertNull(user);//断言user对象为空
}

2.如何基于切面进行声明式编程(AOP)

我们知道,DI-Dependency Injection能够让相互协作的软件组件保持松耦合,而AOP(面向切面编程-aspect-oriented programming)则是把应用中各处的功能分离出来形成可以重用的组件。

系统往往由许多不同的组件组成,每一个组件都有各自负责的功能。除了实现自身核心的功能之外,这些组件常常还承担着额外的责任。诸如 日志事务管理安全这样的系统服务。这些系统服务通常被称为横切关注点,因为它们会跨越系统的多个组件,如果将这些关注点分散到多个组件中,会带来以下问题:

  1. 如果要修改关注点的逻辑,那么就必须修改它所横跨的所有组件模块中的相关实现。即使这些关注点已经被抽象成一个独立的模块,其他部分只是调用它的方法,但方法的调用还是会重复的出现在各个模块中。
  2. 组件会因为那些与自身核心业务无关的代码变得混乱,比如:一个对注册用户的保存操作只应关注如何保存新用户的信息,而不是关注它的日志和事务等。

如下图所示:
这里写图片描述

但是,AOP很好的解决了这个问题,它能够使这些服务模块化,并以声明的方式将它们应用到它们需要影响的组件中去。在使用AOP后,上图中各个组件之间的关系会如下所示:
这里写图片描述

接下来,我们结合之前的例子,在应用中看看AOP是如何进行处理和配置的。
先新建如下代码:

public interfact Hello(){
    void sayHello();
}

public class IHello implements Hello(){
    @Override
    public void sayHello(){
        System.out.println("---HelloWorld---")
    }
}

还记得之前写的三层架构DAO层和Service层吗,它们在spring.xml的配置如下:

<bean id="userDAO" class="com.example.DAO.impl.UserDAOImpl"/>
<bean id="userService" class="com.example.service.impl.UserService.Impl">
    <!-- userDAO属性需要提供setter -->
    <property name="userDAO" ref="userDAO"/>
</bean>

我们在spring.xml中加入管理Hello的组件的配置,在将其AOP配置加上,如下所示:

<!-- 在这里添加Hello的组件配置,可以把它当成一个简单的日志处理 -->
<bean id="iHello" class="com.example.hello.impl.IHello">
<aop:config>
    <!-- 配置切入点 -->
    <aop:pointcut expression="execution(public * com.example.service.impl..*.findUser(..))" 
        id="servicePointcut" />
    <!-- 配置切面,即要执行切入点的地方 -->
    <aop:aspect id="helloAspect" ref="iHello">
        <!-- 配置为在执行方法之前执行切面组件 -->
        <aop:before method="before" pointcut-ref="servicePointcut" />
    </aop:aspect>
</aop:config>

以上配置表示,在切入点表达式所涵盖的方法执行之前,都需先执行切面程序,即先打印出 “—HelloWorld—“,这里就完成了一个简单的切面组件形式的“日志处理“。

总结

现在我们来回顾以下这次介绍的Spring内容:
1.Spring的核心—容器:容器是Spring框架的最核心的部分,它管理着Spring应用中bean的创建、配置和管理。在该模块中,包括了Spring bean工厂,它为Spring提供了DI的功能。基于bean工厂,还有多种Spring应用上下文的实现,每一种都提供了配置Spring的不同的方式。
2.Spring的AOP模块:AOP可以帮助应用对象解耦,借助AOP,可以将遍布系统的关注点(如事物和安全等)从它们所应用的对象中解耦出来。

以上是对DI和AOP进行简单的认识,下一篇我们会对Spring中Bean的装配进行详细的介绍。

猜你喜欢

转载自blog.csdn.net/diagnoa_wleng/article/details/81664617
今日推荐