Skip to content

Spring入门

spring_logo

Spring简介

Spring框架由Rod Johnson开发,2003年发布了第一个版本,目前已发展成为Java EE开发中最重要的框架之一。

Spring为企业应用提供了一个轻量级的解决方案,内容包括:

  • 基于依赖注入的核心机制

  • 基于AOP的声明式事务管理

  • 与多种持久层技术的整合

  • 优秀的Web MVC框架

  • 其他


Spring的组成结构

spring结构图


Spring核心模块

Spring的Core Container是其它模块建立的基础,由Beans(spring-beans)、Core(spring-core)、Context(spring-context)和Expression(spring-expression,Spring表达式语言)等模块组成。

该模块提供了BeanFactory,是工厂模式的一个经典实现,Spring将管理对象称为Bean。

该模块提供了框架的基本组成部分,包括控制反转(Inversion of Control,IoC)和依赖注入(Dependency Injection,DI)功能。

该模块建立在spring-beans和spring-core模块基础上,提供一个框架式的对象访问方式,是访问定义和配置的任何对象媒介。

该模块提供了强大的表达式语言去支持运行时查询和操作对象图。

与AOP和Instrumentation相关的模块有AOP(spring-aop)模块、Aspects(spring-aspects)模块以及Instrumentation(spring-instrument)模块。

该模块提供了一个符合AOP要求的面向切面的编程实现,允许定义方法拦截器和切入点,将代码按照功能进行分离,以便干净地解耦。

该模块提供了与AspectJ的集成功能,AspectJ是一个功能强大且成熟的AOP框架。

该模块提供了类植入(Instrumentation)支持和类加载器的实现,可以在特定的应用服务器中使用。Instrumentation提供了一种虚拟机级别支持的AOP实现方式,使得开发者无需对JDK做任何升级和改动,就可以实现某些AOP的功能。

Spring 4.0以后新增了Messaging(spring-messaging)模块,该模块提供了对消息传递体系结构和协议的支持。

数据访问/集成层由JDBC(spring-jdbc)、ORM(spring-orm)、OXM(spring-oxm)、JMS(spring-jms)和Transactions(spring-tx)模块组成。

该模块提供了一个JDBC的抽象层,消除了繁琐的JDBC编码和数据库厂商特有的错误代码解析。

为流行的对象关系映射(Object-Relational Mapping)API提供集成层,包括JPA和Hibernate。

该模块提供了一个支持对象/XML映射的抽象层实现,如JAXB、Castor、JiBX和XStream。

该模块指Java消息传递服务,包含用于生产和使用消息的功能。

该模块支持用于实现特殊接口和所有POJO(普通Java对象)类的编程和声明式事务管理。

Web层由Web(spring-web)、WebMVC(spring-webmvc)、WebSocket(spring-websocket)和WebFlux(spring-webflux)模块组成。

提供了基本的Web开发集成功能。例如:多文件上传功能、使用Servlet监听器初始化一个IoC容器以及Web应用上下文。

该模块包含用于Web应用程序的Spring MVC和REST Web Services实现。

Spring 4.0后新增的模块,它提供了WebSocket和SockJS的实现,主要是与Web前端的全双工通讯的协议。

该模块是一个新的非堵塞函数式Reactive Web框架,可以用来建立异步的、非阻塞、事件驱动的服务,并且扩展性非常好。(该模块是Spring 5新增模块)

Test(spring-test)模块:该模块支持使用JUnit或TestNG对Spring组件进行单元测试和集成测试。



Spring的优点

  • 低侵入式设计,代码的污染极低。

  • 独立于各种应用服务器。

  • Spring的DI容器降低了业务对象替换的复杂性,提高了组件之间的解耦。

  • Spring的AOP支持通用任务的集中式管理。

  • Spring的ORM和DAO提供了与第三方持久层框架的良好整合,并简化了底层数据库访问。

  • Spring的开放性好,开发者可自由选用Spring框架的部分或全部。


Spring的缺点

  • 中断了应用程序的逻辑,使代码变得不直观;

  • 把逻辑处理由代码化变为配置化,增加了出错的概率,也使后期的维护难度增加;

  • 调试不方便。


如何使用Spring

  • 对于Java SE项目,只需在项目的classpath中增加相应的Spring jar包即可。

  • 对于Web项目,只需要如下两个步骤

    • 拷贝所有jar包到web项目的WEB-INF/lib下

    • 将所需的第三方类库文件复制到Web项目的WEB-INF/lib下

1
2
3
4
5
6
7
<!-- spring-core -->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>4.3.7.RELEASE</version>
</dependency>
<!-- ... -->

依赖注入

IoC:Inverse Of Control

DI: Dependcy Injection

IoC的含义

不创建对象,但是描述创建它们的方式。在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务。容器 (在 Spring 框架中是 IoC 容器) 负责将这些联系在一起。

通过配置创建对象而不是代码

IoC是Spring的核心和基础

IoC实现的基础是工厂模式,所使用的技术主要是java的反射技术。

SimpleFactory模式:应用和具体的实体类分离、解耦。


原理

利用Java Bean的命名约定和Java的动态能力实现数据的自动注入

数据类A
1
2
3
4
public class A{
  int f1;
  //...
}
数据类B
1
2
3
4
public class B{
  A a;  //注入点
  //...
}
1
2
3
4
5
6
7
public static void main (String[] args) {
  //以前的做法
  A a = new A();
  //初始化

  B b = new B();
  b.setA(a);
public static void main (String[] args) {
  Class<?> classB = Class.forName("B");
  B b = classB.newInstance();
  Field[] fields = classB.getDeclaredFields();
  for (Field field : fields) {
    field.setAccessible(true);
    Class<?> fieldType = field.getType(); // 获取成员变量的类型
    Object value = fieldType.newInstance(); // 创建新的对象
    field.set(b, value); // 给成员变量动态赋值
  }

注入实现(配置)

<?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:p="http://www.springframework.org/schema/p" 
  xsi:schemaLocation="http://Www.springframework.org/'schema">
  <bean id="a" class="com.bean.A">
    <property name="f1" value="1"></property>
  </bean>
  <bean id="b" class="com.bean.B">
    <property name="a" value="a"></property>
  </bean>
</beans>
1
2
3
4
ClassPathResource cpr = new ClassPathResource("applicationContext.xml");
XmlBeanFactory factory = new XmlBeanFactory(cpr);
A a = (A)factory.getBean("a");
B a = (B)factory.getBean("a");

注入实现(注解)

1
2
3
4
@Service
public class A{
  //...
}
1
2
3
4
5
6
7
@Controller
public class B{

  @Autowired
  private A a = null;
  //...
}

AOP编程

Spring Boot提供了一种方便的方式来实现AOP编程,即使用Spring AOP框架。Spring AOP框架基于代理模式,通过在目标对象周围织入切面来实现AOP编程。

要使用Spring AOP框架,需要在Spring Boot应用程序中添加以下依赖项:

1
2
3
4
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

然后,可以使用@Aspect注解定义切面类,并使用@Pointcut注解定义切入点。在切面类中,可以使用@Before、@After、@Around等注解定义通知,以在目标方法执行前、后或周围执行额外的逻辑。


示例

以下代码演示了如何使用Spring AOP框架在Spring Boot应用程序中实现日志记录:

@Aspect
@Component
public class LoggingAspect {

    private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);

    @Pointcut("execution(* com.example.demo.*.*(..))")
    public void logMethod() {}

    @Before("logMethod()")
    public void logBefore(JoinPoint joinPoint) {
        logger.info("Entering method: " + joinPoint.getSignature().getName());
    }

    @After("logMethod()")
    public void logAfter(JoinPoint joinPoint) {
        logger.info("Exiting method: " + joinPoint.getSignature().getName());
    }

    @Around("logMethod()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        logger.info("Before method: " + joinPoint.getSignature().getName());
        Object result = joinPoint.proceed();
        logger.info("After method: " + joinPoint.getSignature().getName());
        return result;
    }
}

在上面的代码中,@Aspect注解表示这是一个切面类,@Component注解表示这是一个Spring组件。@Pointcut注解定义了一个切入点,它匹配所有com.example.demo包中的方法。@Before、@After和@Around注解定义了通知,它们分别在目标方法执行前、后和周围执行额外的逻辑。在通知中,可以使用JoinPoint和ProceedingJoinPoint参数来访问目标方法的信息和执行目标方法。

最后,需要在Spring Boot应用程序的配置类中启用AOP:

@SpringBootApplication
@EnableAspectJAutoProxy
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

@EnableAspectJAutoProxy注解启用了Spring AOP框架的自动代理功能,以便在运行时创建代理对象。