Spring


  • 目前主流的Java Web开发框架,是Java世界最成功的框架。
  • Spring由Rod johnson创立,有interface21为基础进行开发最终,于2004年3月24日发布正式版1.0
  • Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架及非入侵式框架。
  • 支持事务处理,对框架进行整合的支持!

组成

img

IoC (控制反转)

指的是将对象的创建权交给 Spring 去创建。使用 Spring 之前,对象的创建都是由我们使用 new 创建,而使用 Spring 之后,对象的创建都交给了 Spring 框架。

IOC推导

  1. 先写UserDao层接口
package com.juran.dao;

public interface UserDao {
    String getUser();
}
  1. 再写UserDao接口实现类
package com.juran.dao;

public class UserDaoImpl implements UserDao{
    @Override
    public String getUser() {
        return  "普通调用成功";
    }
}
  1. 然后再写UserService实现类
package com.juran.service;

public interface UserService {
    String getUser();
}
  1. 最后再写UserService实现类
package com.juran.service;

import com.juran.dao.UserDao;
import com.juran.dao.UserDaoImpl;

public class UserServiceImpl implements UserService{

    private UserDao userDao;
  
    @Override
    public String getUser() {
        userDao = new UserDaoImpl();
        return userDao.getUser();
    }
}
  1. 进行测试
import com.juran.service.UserServiceImpl;
import com.juran.service.UserService;

public class Test {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        String result = userService.getUser();
        System.out.println(result);
    }
}

按照我们原来认知里的操作编写代码,这样是没有问题的

  1. UserDao实现类增加一个
package com.juran.dao;

public class UserDaoImpl2 implements UserDao{
    @Override
    public String getUser() {
        return  "实现类2";
    }
}
  1. 之后我们再去service实现类里修改对应的实现
package com.juran.service;

import com.juran.dao.UserDao;
import com.juran.dao.UserDaoImpl;
import com.juran.dao.UserDaoImpl2;

public class UserServiceImpl implements UserService{

    private UserDao userDao;

    @Override
    public String getUser() {
        userDao = new UserDaoImpl2();
        return userDao.getUser();
    }
}

那如果我们再写一个UserDao接口的实现类呢?我们是不是又按照相同的方法去修改service层,假设需求量大这种方法就完全不适用了。每次改动都需要修改大量的service实现类,这种方法耦合性太高,独立性就比较差。我们所需要的是高内聚度和低耦合。

  1. 解决耦合性较高问题

我们可以在service实现类中留一个setter接口,进而可以实现动态选择Dao层的实现类

package com.juran.service;

import com.juran.dao.UserDao;

public class UserServiceImpl implements UserService{

    private UserDao userDao;

    //使用set接口进行动态实现类选择。
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public String getUser() {
        return userDao.getUser();
    }
}
  1. 测试
import com.juran.dao.UserDaoImpl;
import com.juran.dao.UserDaoImpl2;
import com.juran.service.UserServiceImpl;

public class Test {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();

        userService.setUserDao(new UserDaoImpl());

        String result1 = userService.getUser();

        System.out.println(result1);

        //再次使用setter去选择实现类
        userService.setUserDao(new UserDaoImpl2());

        String result = userService.getUser();

        System.out.println(result);
    }
}

这种思想,从本质上解决了问题,我们的程序员不再去管理对象的创建了,更多的去关注业务的实现,耦合性大大降低,这也就是IOC的原形型。

IOC本质

控制反转是一种设计思想,DI(依赖注入)是实现IOC的一种方法。没有IOC的程序中,我们使用面向对象编程,对象的创建与对象之间的依赖关系完全硬编码再程序中,对象创建由程序自己控制,控制反转后将对象的创建交给第三方,控制反转:获得依赖对象的方式反转了。

通常,每个单独的 XML 配置文件都代表您架构中的一个逻辑层或模块,您可以使用应用程序上下文构造函数从所有这些 XML 片段加载 bean 定义。

控制反转时通过一种描述(xml或者注解),通过第三方去生产或获取特定对象的方式,再spring中实现控制反转的是Ioc容器,其实现方法为依赖注入。

控制反转(IOC)大致可以理解为程序由主动执行,变成被动接收

AOP(面向切面编程)

用来封装多个类的公共行为,将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP 还解决一些系统层面上的问题,比如日志、事务、权限等。

AOP核心业务功能 及 周边功能

  • 核心业务功能::登录、增加数据、删除数据
  • 周边功能:性能、日志及食物管理登录

周边思想即为spring中的Aop切面思想。

在AOP思想中,核心业务功能及切面功能是独立开发的,然后将核心功能与切面功能编织在一起,这就是AOP思想。

AOP 目的

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

AOP 当中的概念:

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

AOP 编程

  • 在service包中创建类【ProductService】类
package com.juran.service;

public class ProductService {
    public void doSomeService(){
        System.out.println("doSomeService");
    }
}
  • XML文件中装配该Bean:
<bean name="productService" class="com.juran.service.ProductService"/>
  • 编写测试类,运行测试。

  • 在 Packge【aspect】下准备日志切面 【LoggerAspect】类:
package com.juran.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;
    }
}
  • 在 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="com.juran.service.ProductService"/>

    <bean id="loggerAspect" class="com.juran.aspect.LoggerAspect"/>

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

        <!-- what:做什么增强 -->
        <aop:aspect id="logAspect" ref="loggerAspect">
            <!-- when:在什么时机(方法前/后/前后) -->
            <aop:around pointcut-ref="loggerCutpoint" method="log"/>
        </aop:aspect>
    </aop:config>

</beans>
  • 再次运行 TestSpring 中的测试代码,代码并没有改变,但是在业务方法运行之前和运行之后,都分别输出了日志信息:

最后修改:2021 年 11 月 25 日
如果觉得我的文章对你有用,请随意赞赏