【Spring实战读书笔记】Spring之旅

雨点打透心脏的1/2处 2023-07-23 03:51 171阅读 0赞

Spring可以做很多事情,但是这个事情底层都依赖于2个核心特征:依赖注入(DI)和面向切面编程(AOP)

概念:POJO:简单java对象,Plain Old Java Object,在Spring中基本可以等同于javabean

为了简化Java开发的复杂性,Spring采用了4个关键策略

(1)基于POJO的轻量级和最小侵入性编程

(2)基于DI和面向接口实现松耦合

(3)基于切面和惯例进行声明式编程

(4)通过切面和模板减少样板式代码

1、Spring减少侵入性代码,保持POJO的简洁

在早期的框架如Struts等,会要求应用继承他们的类或实现他们的接口,这就导致了应用与框架绑定。而在Spring中会尽量避免这种框架代码与应用代码耦合的情况出现,获取会有在代码中加入Spring注解的情况,但是它本身还是一个POJO。为了能够实现这种解绑,其方式之一就是使用DI来装配bean

2、DI依赖注入

实际开发中,不可能只由一个类负责全部的事情,一定存在多个类之间的调用。一般情况下类A调用B的方法时,会在A中new一个B的对象,然后调用之。这样必然导致了高耦合。

所以我们可以考虑以DI方式处理,对象的依赖关系将由系统中负责协调各对象的第三方组件在创建对象的时候进行设定,对象本身无需自行创建或管理他们的依赖关系。更重要的是,传入的类型是一个接口,而不是一个具体的类,任何实现了Account的类都可以被注入进来。Bank并没有与任何特定的Account实现类发生耦合。

  1. public interface Account {
  2. public void addMoney();
  3. public void subtractMoney();
  4. }
  5. public class Bank {
  6. private Account account; // account是接口
  7. public Bank(Account account){
  8. this.account = account;
  9. }
  10. public void save(){
  11. account.addMoney();
  12. }
  13. }

现在ObjectA可以接受任何一种实现了InterfaceB的类的注入。为了能够将具体的类注入到ObjectA中,我们需要进行一些配置。即装配:创建应用组件之间协作的行为通常成为装配

  1. public class Account1 implements Account {
  2. @Override
  3. public void addMoney() {
  4. System.out.println("+100");
  5. }
  6. @Override
  7. public void subtractMoney() {
  8. System.out.println("-100");
  9. }
  10. }
  11. <?xml version="1.0" encoding="UTF-8"?>
  12. <beans xmlns="http://www.springframework.org/schema/beans"
  13. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  14. xsi:schemaLocation="http://www.springframework.org/schema/beans
  15. http://www.springframework.org/schema/beans/spring-beans.xsd">
  16. <bean id="bank" class="test.Bank">
  17. <constructor-arg ref="account1"/>
  18. </bean>
  19. <bean id="account1" class="test.Account1">
  20. </bean>
  21. </beans>

在上面的配置文件中,ObjectA和ObjectB都被声明为Spring中bean,ObjectA bean在构造时传入了ObjectB的引用,并将其作为构造器参数。除了上面的xml方式的配置,还可以使用基于Java的配置。不管使用哪种方式,其作用是相同的。ObjectA依赖于InterfaceB,但是却并不知道传递给他的是什么类型的InterfaceB,也不知道来自哪里。这样就可以在不改变依赖的类(接口)的情况下,修改依赖关系。

Spring使用应用上下文(ApplicationContext)装载bean的定义并把他们组合在一起,Spring提供了多种应用上下文的实现,如ClassPathXMLApplicationContext可以用来加载xml配置文件。还有其他多种应用上下文,根据具体情况使用。

  1. import org.springframework.context.support.ClassPathXmlApplicationContext;
  2. public class TestMain {
  3. public static void main(String[] args) {
  4. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/META_INF/spring.xml")
  5. }
  6. }

3、AOP切面

DI能够让互相写作的软件组件保持松耦合,而面向切面编程(AOP)允许你把遍布应用各处的功能分离出来形成可以重用的组件。

最常见的AOP应用场景就是日志打印和事务控制。每一个组件的开发都可能设计到日志和事务,但是这并不是组件自身的核心业务,他们分散在代码的各处,显然增加了维护的成本。AOP能够是这些服务模块化,并以声明的方式将他们应用到各组件中去。使得各个组件具有更高的内聚性并更关注与自身的业务,不需要了解涉及系统服务所带来的复杂性。AOP能够确保POJO的简洁性。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3Rhb3hpdXhpYQ_size_16_color_FFFFFF_t_70

现在想要在Bank的save方法执行前后加上日志,用于记录save的动作。只需要先定义一个log类,然后做一些AOP相关的配置即可。原Bank代码无需做任何的改动。

  1. public class Log {
  2. public void logBefore(){
  3. System.out.println("you add 100");
  4. }
  5. public void logAfter(){
  6. System.out.println("you subtrace 100");
  7. }
  8. }
  9. <?xml version="1.0" encoding="UTF-8"?>
  10. <beans xmlns="http://www.springframework.org/schema/beans"
  11. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  12. xmlns:aop="http://www.springframework.org/schema/aop"
  13. xsi:schemaLocation="http://www.springframework.org/schema/beans
  14. http://www.springframework.org/schema/beans/spring-beans.xsd
  15. http://www.springframework.org/schema/aop
  16. http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
  17. <bean id="bank" class="test.Bank">
  18. <constructor-arg ref="account1"/>
  19. </bean>
  20. <bean id="account1" class="test.Account1">
  21. </bean>
  22. <bean id="logger" class="test.Log">
  23. </bean>
  24. <aop:config>
  25. <aop:aspect ref="logger">
  26. <aop:pointcut id="log" expression="execution(* *.save(..))"/>
  27. <aop:before pointcut-ref="log" method="logBefore"/>
  28. <aop:after pointcut-ref="log" method="logAfter"/>
  29. </aop:aspect>
  30. </aop:config>
  31. </beans>

首先,把Log声明为一个bean,并在中引用这个bean。aop:pointcut是切入点,并配置表达式expression属性来选择所应用的通知。aop:before和aop:after是前置通知和后置通知,分别在save方法的前后被调用。

面试题,简单介绍一下你对spring的理解

什么是依赖注入

什么是AOP

DI和IoC的关系

发表评论

表情:
评论列表 (有 0 条评论,171人围观)

还没有评论,来说两句吧...

相关阅读