Spring实战读书笔记Spring之旅
Posted xiueer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring实战读书笔记Spring之旅相关的知识,希望对你有一定的参考价值。
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实现类发生耦合。
public interface Account
public void addMoney();
public void subtractMoney();
public class Bank
private Account account; // account是接口
public Bank(Account account)
this.account = account;
public void save()
account.addMoney();
现在ObjectA可以接受任何一种实现了InterfaceB的类的注入。为了能够将具体的类注入到ObjectA中,我们需要进行一些配置。即装配:创建应用组件之间协作的行为通常成为装配
public class Account1 implements Account
@Override
public void addMoney()
System.out.println("+100");
@Override
public void subtractMoney()
System.out.println("-100");
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bank" class="test.Bank">
<constructor-arg ref="account1"/>
</bean>
<bean id="account1" class="test.Account1">
</bean>
</beans>
在上面的配置文件中,ObjectA和ObjectB都被声明为Spring中bean,ObjectA bean在构造时传入了ObjectB的引用,并将其作为构造器参数。除了上面的xml方式的配置,还可以使用基于Java的配置。不管使用哪种方式,其作用是相同的。ObjectA依赖于InterfaceB,但是却并不知道传递给他的是什么类型的InterfaceB,也不知道来自哪里。这样就可以在不改变依赖的类(接口)的情况下,修改依赖关系。
Spring使用应用上下文(ApplicationContext)装载bean的定义并把他们组合在一起,Spring提供了多种应用上下文的实现,如ClassPathXMLApplicationContext可以用来加载xml配置文件。还有其他多种应用上下文,根据具体情况使用。
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestMain
public static void main(String[] args)
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/META_INF/spring.xml")
3、AOP切面
DI能够让互相写作的软件组件保持松耦合,而面向切面编程(AOP)允许你把遍布应用各处的功能分离出来形成可以重用的组件。
最常见的AOP应用场景就是日志打印和事务控制。每一个组件的开发都可能设计到日志和事务,但是这并不是组件自身的核心业务,他们分散在代码的各处,显然增加了维护的成本。AOP能够是这些服务模块化,并以声明的方式将他们应用到各组件中去。使得各个组件具有更高的内聚性并更关注与自身的业务,不需要了解涉及系统服务所带来的复杂性。AOP能够确保POJO的简洁性。
现在想要在Bank的save方法执行前后加上日志,用于记录save的动作。只需要先定义一个log类,然后做一些AOP相关的配置即可。原Bank代码无需做任何的改动。
public class Log
public void logBefore()
System.out.println("you add 100");
public void logAfter()
System.out.println("you subtrace 100");
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<bean id="bank" class="test.Bank">
<constructor-arg ref="account1"/>
</bean>
<bean id="account1" class="test.Account1">
</bean>
<bean id="logger" class="test.Log">
</bean>
<aop:config>
<aop:aspect ref="logger">
<aop:pointcut id="log" expression="execution(* *.save(..))"/>
<aop:before pointcut-ref="log" method="logBefore"/>
<aop:after pointcut-ref="log" method="logAfter"/>
</aop:aspect>
</aop:config>
</beans>
首先,把Log声明为一个bean,并在<aop:aspect>中引用这个bean。aop:pointcut是切入点,并配置表达式expression属性来选择所应用的通知。aop:before和aop:after是前置通知和后置通知,分别在save方法的前后被调用。
面试题,简单介绍一下你对spring的理解
什么是依赖注入
什么是AOP
DI和IoC的关系
以上是关于Spring实战读书笔记Spring之旅的主要内容,如果未能解决你的问题,请参考以下文章