【读过的书,留下的迹】Spring实战(第3版)

第1章:Spring之旅

  • 简单得说,spring通过面向POJO编程、依赖注入、AOP和模板技术来简化Java开发的复杂性

第2章:装配Bean

    <!-- 依赖注入应该引入以下库,以Maven为例,其他的包会自动下载 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.7.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>javax.inject</groupId>
        <artifactId>javax.inject</artifactId>
        <version>1</version>
    </dependency>

(1)声明Bean

<?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: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/context 
     http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <bean id="duke" class="spring.test.bean.Juggler">
        <!-- 通过构造器注入 -->
        <constructor-arg value="15" />
        <!-- 通过构造器注入引用对象 -->
        <constructor-arg ref="sonnet29" />
    </bean>

    <!-- 通过工厂方法创建Bean -->
    <bean id="stage" class="spring.test.bean.Stage"
        factory-method="getInstance" />

    <!-- Bean的作用域
    singleton:在每一个Spring容器中,一个Bean定义只有一个对象实例
    prototype:允许Bean的定义可以被实例化任意次
    request、session、global-session -->
    <bean id="duke" class="spring.test.bean.Ticket" 
        scope="prototype"/>

    <!-- 注入Bean属性,通过setter -->
    <bean id="kenny" class="spring.test.bean.Instrumentalist">
        <property name="song" value="Jingle Bells" />
        <property name="instrument" ref="saxophone" />
        <!-- 装配集合,list、set、map、props等 -->        
    </bean>

    <!-- 使用表达式装配 SpEL,SpEl语法跟java差不多。一些用法:
    1、something?.pro,判断是否为空,再取值
    2、T(java.lang.Math).PI,T()获取类 -->
    <bean id="saxophone" class="spring.test.bean.Saxophone" >
        <property name="saxophone" value="#{SpEL}"
    </bean>
</beans>

第3章:最小化Spring XML配置

(1)自动装配Bean属性

  • byName:把与Bean得属性具有相同名字的其他Bean自动装配
  • byType:相同属性的
  • constructor:与构造器具有相同属性的
  • autodetect:首先尝试constructor,再尝试byName
<beans
    <!-- 省略一大堆 -->
    <!-- 默认自动装配 -->
    default-autowire="byType">
    <bean id="duke" class="spring.test.bean.Juggler"
        autowire="byType">
        <!-- 可以覆盖默认 -->
    </bean>
    <bean id="duke2" class="spring.test.bean.Juggler"
        primary="false">
        <!-- 多个Bean时候,可以设置首选,默认是true,得把其他的全设为false -->
    </bean>
    <bean id="duke2" class="spring.test.bean.Juggler"
        autowire-candidate="false">
        <!-- 不让这个Bean成为autowire的扫描对象 -->
    </bean>
</beans>

(2)使用注解装配

<beans/> <!-- 省略一大堆 --> 
    <!-- 开启注解装配 -->
    <context:annotation-config>
    <bean id="duke3" class="spring.test.bean.Juggler" >
        <qualifier value="test" />
        <!-- 限定值设置 -->
    </bean>
</beans>
  • 使用@Autowired
    • @Qualifier(“id”)
    • @Qualifier(“value”)
    • 自定义Qualifier,新建一个类
  • 使用@Inject:跟Autowired用法基本一样,是Java依赖注入规范
    • 配套使用的是 @Named 加限定

(3)自动检测Bean

  • 转为Bean的注解
    • @Component:通用的构造型注解,标识伪Spring组件
    • @Controller:SpringMVC controller注解
    • @Repository:标识数据仓库
    • @Service:标识服务
<beans/> <!-- 省略一大堆 --> 
    <!-- 开启自动检测 -->
    <context:component-scan base-package="spring.test.bean">
    <context:include-filter type="assignable"
        expression="some.class" />
    <context:exclude-filter type="assignable"
        expression="some.class" />
    </context:component-scan>
</beans>
  • 过滤组建扫描
    • annotation:过滤注解的类
    • assignable:过滤派生于注解的类
    • 等等

(4)使用基于Java的配置

利用@Configuration注解来标识Java配置类

第4章:面向切面的Spring

    <!-- 面向切面应该引入以下的库,以maven为例 -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.10</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.8.10</version>
    </dependency>
    <dependency>
        <groupId>aopalliance</groupId>
        <artifactId>aopalliance</artifactId>
        <version>1.0</version>
    </dependency>

在软件开发中,分布于应用中多处的功能被称为横切关注点。通常,这些横切关注点从概念上是与应用的业务逻辑相分离的。将这些横切关注点与业务逻辑相分离正是面向切面编程所要解决的。

(1)定义切点

execution(* spring.test.bean.Class.function(..)) && others

(2)在XML中声明切面

<?xml version="1.0" encoding="UTF-8" ?>
<beans <!-- 新添加 -->
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/aop 
     http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    <bean
        id="poeticDuke"
        class="spring.test.bean.PoeticJuggler">
    </bean>
    <bean
        id="audience"
        class="spring.test.bean.Audience">
    </bean>
    <aop:config>
        <aop:aspect ref="audience">
            <!-- 定义切点 -->
            <aop:pointcut
                id="performance"
                expression="execution(* spring.test.bean.Performer.perform(..))" />
            <aop:before
                method="takeSeats"
                pointcut="execution(* spring.test.bean.Performer.perform(..))" /> <!-- perform为调用的方法 -->
            <aop:after-returning
                method="applaud" <!-- applaudaudience的方法 -->
                pointcut-ref="performance" />
        </aop:aspect>
    </aop:config>
</beans>
  • 声明环绕通知
// Audience 类中定义此方法,ProceedingJoinPoint作为方法的入参
public void watchPerformance(ProceedingJoinPoint joinPoint) {
    try {
        // do something
        // 谨记必须调用proceed方法,否则本通知会阻塞被通知的方法,即perform()方法
        joinpoint.proceed();
        // do other things
    }
}
    <aop:config>
        <aop:aspect ref="audience">
            <aop:around
                method="watchPerformance()" <!--do something,然后调用perform(),再do other things -->
                pointcut="execution(* spring.test.bean.Performer.perform(..))" /> <!-- perform为调用的方法 -->
        </aop:aspect>
    </aop:config>
  • 为已有Bean引入接口
<aop:aspect>
    <aop:declare-parents
        <!-- 匹配已有的bean -->
        types-matching="spring.test.bean.Performer+"
        <!-- 需要添加到bean的接口 -->
        implement-interface="spring.test.bean.NewInterface"
        <!-- 接口的默认实现方法 -->
        default-impl="spring.test.bean.InterfaceInstance"
    />
</aop:aspect>

(3)基于注解的切面

@Aspect
public class Audience {
    @Pointcut("execution(* spring.test.bean.Performer.perform(..))")
    public void performance() {

    }

    @Before("performance()")
    public void takeSeats() {
        System.out.println("Take seat");
    }
}
<!-- 添加此配置 -->
<aop:aspectj-autoproxy />
  • 基于注解的同样可以
    • 注解环绕通知
    • 传递参数给所标注的通知
    • 引入新接口

Spring切面仍然只是基于代理的,而且限于通知方法的调用。如果需要的功能超过了Spring所支持的方法代理,那么可以考虑使用AspectJ,Spring只有简单功能的aop。

第5章:装配Bean

  • JDBC只提供了SQLException异常,以至发生异常不知道问题在哪。spring提供了多个数据访问异常,分别描述他们抛出时所对应的问题
  • 针对不同持久化平台,spring提供多个可选的模版
  • spring针对不同模版提供了对应的DAO支持类

(1)配置数据源

  • 使用JDNI数据源
    • 需要在web server中配置数据源,需作相应部署
  • 使用数据源连接池
    • 第三方依赖包中包含了两个数据源的实现类包,其一是Apache的DBCP,其二是 C3P0(推荐使用)
  • 基于JDBC驱动数据源
    • 没有使用连接池,项目中少用
<bean id="dataSource class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://ip:3306/zhihu" />
    <property name="username" value="root" />
    <property name="password" value="" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource" />
</bean>
<bean id="mysql" class="spring.test.db.Mysql">
    <property name="jdbcTemplate" ref="jdbcTemplate" />
</bean>

(2)使用JDBC DAO支持类

  • DAO支持类中定义好了获取Jdbc模版的相应方法

(3)Java持久化API

  • spring还支持 java persistence API,JPA是一套规范,Hibernate,TopLink,JDO他们是一套产品,这些产品实现了这个JPA规范,JPA有点像JDBC,为各种不同的ORM技术提供一个统一的接口,方便把应用移植的不同的ORM技术上。

第6章:事务管理

Spring提供的事务管理:

  • 编码式
    • 对事务边界控制精确,但是Spring的编码式事务是侵入式的,需修改类的实现
  • 声明式
    • 通常情况下,事务需求不会要求很高的事务边界控制,故用的较多

(1)事务管理器

  • Spring并不直接管理事务,而是提供了多种事务管理器,将事务管理的职责委托给其他平台相关的事务实现



example: JDBC事务

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

(2)声明式事务

  • 属性
    • 传播行为:新的事务应该被启动还是被挂起,或者方法是否要在事务环境中运行
    • 隔离级别:一个事务可能受其他并发事务影响的程度
    • 只读
    • 事务超时
    • 回滚规则





(3)在xml中定义事务

<tx:advice id="txAdvice" transaction-manager="yourManager">
    <tx:attributes>
        <!-- 采用方法名匹配 -->
        <tx:method name="save*" propagation="REQUIRED" />
        <tx:method name="*" propagation="SUPPORTS" read-only="true" />
    </tx:attributes>
</tx:advice>
<aop:config>
    <!-- 采用切点匹配 -->
    <aop:advisor
        pointcut="execution(* *..SpitterService.*(..))"
        advice-ref="txAdvice" />
</aop:config>

(4)在注解驱动中定义

<tx:annotation-driver transaction-manager="yourManager" />
@Transactional(propagation=Propagation.SUPPORTS, readOnly=true)
public class ServiceImpl implements Service {
...
    @Transactional(propagation=Propagation.REQUIRED, readOnly=false)
    public void addSomething() {
    }
}

第7章:使用Spring MVC

  • 与大多数基于Java的Web框架一样,Spring MVC所有的请求都会通过一个前端控制器Servlet——DispatcherServlet

(1)搭建Spring MVC

web.xml

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <!-- 声明DispatcherServlet,通过这一前端控制器Servlet,
       委托给其他组件来执行实际的处理 -->
  <servlet>
    <!-- DispatcherServlet将尝试从一个名为WEB-INF/weibo-servlet.xml加载应用上下文 -->
    <servlet-name>weibo</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>weibo</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

</web-app>

weibo-servlet.xml

    <!-- 静态资源请求 -->
    <mvc:resources
        mapping="/resources/**"
        location="/resources/" />

    <!-- mvc注解扫描 -->
    <mvc:annotation-driven />
    <context:component-scan base-package="spring.test.mvc" />

    <!-- 配置view的解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 默认InternalResourceViewResolver创建的view是InternalResourceView
             若需要使用jstl标签,需配置viewclass将其替换为JstlView -->
        <property
            name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
        <property
            name="prefix"
            value="/WEB-INF/views/" />
        <property
            name="suffix"
            value=".jsp" />
    </bean>

(2)基本控制器

@Controller
public class HomeController {
    public static final int DEFAULT_WEIBO_PER_PAGE = 25;

    // 映射路径
    @RequestMapping({"/", "/home"})
    public String showHomePage(Map<String, Object> model) {
        model.put("weibos", new WeiboHome());
        return "home";
    }
}

(3)控制器输入

@Controller
@RequestMapping("/weiboo") // 定义大的路径
public class Weiboo {
    @RequestMapping(value="/boo", method=GET) // 路径为/weiboo/boo?name=lin
    // 请求参数如果与下面的参数名一样,可省略@RequestParam("name")
    // model是spring自己定义的map,会根据addAttribute的类,定义key
    public String listWeiboo(@RequestParam("name") String name, Model model) {
        model.addAttribute("name", name);
        model.addAttribute("time", "2017");
        return "weiboo";
    }
}

weiboo.jsp

<!-- 我的情况不加这句ei表达式不起作用 -->
<%@ page isELIgnored="false" %>
<div>
    <h1>This is weiboo of ${name}</h1>
    <h1>Time is ${time}</h1>
</div>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值