Spirng+In+Action(Craig Walls Ryan Breidenbach)

目录

  1.开始Spring之旅(简介)

  2.装配Bean(IoC)

  3.创建切面(AOP)

  。。。

第一章:开始Spring之旅

  1.1 为什么使用Spring:简化了企业级系统开发。

    1.1.1 javaEE开发者的一天:EJB功能强大,即使简单的应用系统都需要各种组件的支持,使用较为复杂。

    1.1.2 Spring的承诺:

      1.好的设计比实现技术更重要

      2.通过接口松散耦合的JavaBean是一个很好的模型

      3.代码应该容易被测试

  1.2 Spring是什么:Spring是一个轻量级的IOC和AOP容器框架

    轻量级:1MB多的jar包源代码

    非侵入式:基于Spring开发系统中的对象一般不依赖于Spring框架中的类

    反向控制:创建一个对象时,需要在容器系统中寻找所对应的类,而反向控制,则是在容器启动实例化时,主动为引用的实例类注入依赖类对象

    面向切面:提取多种业务的共性,形成一种过滤效果,使开发者只需要关注具体的逻辑业务问题

    容器:可以管理系统中对象的生命周期与设置(BeanFactory/ApplicationContext)

    框架:通过XML文件配置组合

    spring组成模块:

      

  1.3 开始Spring之旅

//接口定义
package com.cys.test;
public interface GreetingService { public void sayGreeting(); }
//具体实现类
package com.cys.test;

public class GreetingServiceImpl implements GreetingService {
    private String greeting;
    public GreetingServiceImpl() {}
    public GreetingServiceImpl(String greeting) {
        this.greeting = greeting;
    }
    public void sayGreeting() {
        System.out.println("GreetingServiceImpl [greeting=" + greeting + "]");        
    }
    public void setGreeting(String greeting) {
        this.greeting = greeting;
    }
}
//主函数类
package com.cys.test;

import java.io.FileInputStream;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;

public class HelloApp{
    public static void main(String[] args) throws Exception{
        BeanFactory factory = new XmlBeanFactory(new FileInputStream("spring-beans.xml"));
        GreetingService greeting = (GreetingService)factory.getBean("greetingService");
        greeting.sayGreeting();
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<!-- xml配置文件 -->
<beans> 
    <!-- 无参数构造 -->
    <bean id="greetingService" class="com.cys.test.GreetingServiceImpl">
        <property name="greeting" value="Hello World" />
    </bean>
    <!-- 带参数构造 -->
    <bean id="greetingService" class="com.cys.test.GreetingServiceImpl">
        <constructor-arg>
            <value>Hello World</value>
        </constructor-arg>
    </bean>
</beans> 

  1.4 理解反向控制(依赖注入):获得依赖对象的方式反转

  1.5 应用AOP:IoC使软件组件松散连接成为可能,AOP让你能够捕捉经常使用的功能,把该功能转化为组件

    

  1.6 Spring比较

    

   小结:

  

  

第二章:装配Bean

  2.1 容器是Spring框架的核心:BeanFactory、ApplicationFactory

    2.1.1 BeanFactory:Bean简单工厂管理模式

      常见实现类:XmlBeanFactory

        BeanFactory factory = new XmlBeanFactory(new FileInputStream("beans.xml"));

        MyBean myBean = factory.getBean("myBeanId");

    2.1.2 ApplicationFactory:提供更多附加的功能(文本信息解析工具、载入文件资源、注册监听器)

      常见实现类:ClassPathXmlApplicationFactory、FileSystemXmlApplicationFactory、XmlWebApplicationFactory

        ApplicationFactory factory = new ClassPathXmlApplicationFactory("beans.xml");

        ApplicationFactory factory = new FileSystemXmlApplicationFactory("c:/beans.xml");

        XmlWebApplicationFactory:见第八章

    2.1.3 Bean生命周期

  

    Bean工厂容器与ApplicationContext容器的唯一区别:ApplicationContext容器会调用ApplicationContextAware接口的setApplicationContext()方法

  2.2 基本配置(Beans.xml)

    2.2.1 xml配置:<beans><bean id="" class=""/><beans ...></beans>

    2.2.2 添加一个Bean

      bean属性:

        单实例与原型:singleton="true"--单实例(默认)  singleton="false"--原型(每次getBean(),获取的对象都是一个新的)

        实例化与销毁:init-method="name1"--初始化时调用name1()方法  destroy-method="name2"--销毁时调用name1()方法

    2.2.3 set属性注入

      基本类型注入(int、String、...):<property name="xxx"><value>xxx(值)</value></property>

      引入其他bean:<property name="xxx"><ref bean="xxx(beanId)"></property>(常用)、<property name="xxx"><bean class="" /></property>(不常用)

      List与数组:<property name="xxx"><list><value>xxx(值)</value><ref ...><...></list></property>(值可以是任意元素)

      Set:<property name="xxx"><set><value>xxx(值)</value><ref ...><...></set></property>(值可以是任意元素)

      Map:<property name="xxx"><map><entry key="xxx1"><value>xxx(值)</value></entry><entry key="xxx2"><ref ...></entry><entry key="..."><...></entry></map></property>(值可以是任意元素)

      Property:<property name="xxx"><prop key="xxx1">xxx(值)</prop><prop key="xxx2">xxx(值)</prop>...</property>(值只能是String类型,不需要<value>标签)

      设置null:<property name="xxx"><null/></property>(默认可以不设置,这是显示装配)

    2.2.4 构造函数注入

      与set同理,<property>改为<constructor-arg>,并提供了index、tyep属性

      index:参数序号,从0开始--<constructor-arg index="0"><value><ref ...>...</constructor-arg>  

      type:属性类型(java.lang.String)--<constructor-arg type="java.lang.String"><value><ref ...>...</constructor-arg>

      默认情况可以不设置,在多个参数类型相同时,为区分参数先后顺序,必须设置index属性

      set注入与构造函数注入区别:构造函数可以强制关联依赖关系,达到初始化一个完整可用的对象

  2.3 自动装配Bean(一般不考虑)

    。。。

  2.4 特殊bean:实现spring特定的接口,在bean生命周期的过程中处理bean信息

    2.4.1 对bean进行后处理:实例化后初始化前--初始化后

      接口:BeanPostProcessor

        覆盖方法(实例化后初始化前方法):postProcessBeforeInitialization(Object bean, String name)

        覆盖方法(初始化后方法):postProcessAfterInitialization

      注册bean:

        Bean工厂容器:factory.addBeanPostProcssor(BeanPostProcessor接口类的实现类)

        上下文容器:在xml配置文件里添加实现BeanPostProcessor接口的类bean即可,上下文容器会自动识别:<bean id="" class="" />

      spring框架自动BeanPostProcessor实现

        。。。

    2.4.2 对Bean工厂进行后处理:实例化之前,即容器加载bean配置文件定义,开始实例化每个bean之前

      接口:BeanFactoryPostProcessor

        覆盖方法(实例化之前):postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)

    2.4.3 分散配置:Spring容器定义bean信息集中在一个配置文件里,不利于维护和修改,容易形成硬性编码

      ApplicationContext上下文容器自带引用加载properties类型文件实现类:PropertyPlaceholderConfigurer

      在xml配置文件里添加以下代码,加载属性,可以使用${key}来获取properties属性文件所对应的值     

      <bean id="xxx" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

        <property name="location">

          <value>xxx.properties</value>

            <value>...</value>

        <property>

      </bean>

    2.4.4 属性类型编辑器:对参数值类型转换接收

      。。。

    2.4.5 解析文本信息

      。。。

    2.4.6 监听事件:ApplicationContext容器在生命周期中默认会触发许多事件

      触发事件:ContextCloseEvent--应用上下文关闭时触发  ContextRefreshedEvent--应用上下文初始化或刷新时触发  RequestHandledEvent--Web服务应用上下文中请求被处理后触发

        这个三个事件类都是抽象类org.springframework.context.ApplicationEvent的子类

      监听事件处理:实现org.springframework.context.ApplicationListener接口,实现onApplicationEvent方法,并在spring配置文件里注册bean

    2.4.7 设置触发事件

      。。。

    2.4.8 感知bean:用于获取bean属性信息

      常用接口:BeanNameAware--获取beanID  BeanFactoryAware--获取bean容器  ApplicationContextAware--获取bean容器

        bean类实现BeanNameAware接口,获取beanID值

          //声明属性,设置属性值,注册bean后,自动加载属性赋值          

          public class GetBeanName implements BeanNameAware{
            private String beanName;
            public void setBeanName(String beanName){
              this.beanName = beanName;
            }
          }

        bean类实现BeanFactoryAware接口,获取容器

          //声明属性,设置属性值,注册bean后,自动加载属性赋值

          public class GetBeanFactory implements BeanFactoryAware{
            private BeanFactory factory;
            public void setBeanFactory(BeanFactory factory){
              this.factory= factory;
            }
          }

        bean类实现ApplicationContextAware接口,获取容器

          //声明属性,设置属性值,注册bean后,自动加载属性赋值

          public class GetBeanFactory implements ApplicationContextAware{
            private ApplicationContext context;
            public void setApplicationContext(ApplicationContext context){
              this.context = context;
            }
          }

    

第三章:创建切面

  3.1 AOP介绍

    3.1.1 定义AOP术语:切面(Aspect)、连接点(Joinpotion)、通知(Advice)、切入点(Pointcut)、引入(Introduction)、目标对象(Target)、代理(Proxy)、织入(Weaving)

    3.2.2 Spring的AOP实现

        。。。

  3.2 创建通知

    

    3.2.1 前置通知:目标方法前执行

//创建通知实体类,实现前置通知接口,复写接口方法
public class WelcomeAdvice implements MethodBeforeAdvice{
    //Method:目标方法
    //args:目标方法参数列表
    //target:目标对象
    public void before(Method method, Object[] args, Object target){
        //具体通知逻辑业务
    }
}
<!-- 配置文件 -->
<bean id="xxx1" class="目标对象" />

<bean id="xxx2" class="具体通知对象">

<bean id="xxx3" class="org.springframework.aop.framework.ProxyFactoryBean(代理对象)">
    <property name="proxyInterfaces(目标对象实现的接口类)">
        <value>xxx.xxxxx.xxxx.xxx4</value>
    </property>
    <property name="interceptorNames(通知列表)">
        <list>
            <value>xxx2</value>
            ...
        </list>
    </property>
    <property name="target(目标对象)">
        <value>xxx1</value>
    </property>
</bean>

    3.2.2 后置通知:目标方法后执行

//创建通知实体类,实现后置通知接口,复写接口方法
public class ThankYouAdvice implements AfterReturningAdvice{
    //returnValue:目标方法的返回值
    //Method:目标方法
    //args:目标方法参数列表
    //target:目标对象
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target){
        //具体通知逻辑业务
    }
}

    3.2.3 环绕通知:目标方法前后都行,但需要手动调用目标方法并返回值

//创建通知实体类,实现环绕通知接口,复写接口方法
public class OnePerCustomerInterceptor implements MethodInterceptor{
    //MethodInterceptor:封装目标对象相关类
    public Obeject invoke(MethodInvocation invocation){
      //手动调用目标方法,返回目标方法返回值
        Obeject xxx = invocation.proceed();
        //手动返回
        return xxx;
    }
}

    3.2.4 异常通知:调用目标方法抛出异常时执行

      实现ThrowsAdvice接口,并覆盖void afterThrowing(Throwable throwable)与void afterThrowing(Throwable throwable,  Method method, Object[] args, Object target)任意一个方法

    3.2.5 引入通知:给目标对象添加行为或属性

      。。。

  3.3 定义切入点:定义通知在那些地方应用

    3.3.1 在Spring中定义切入点

//切入点核心接口
public interface Poincut{
  //类过滤
  ClassFilter getClassFilter();
  //方法过滤
  MethodMatcher getMethodMatcher();
}
//类过滤接口
public interface ClassFilter{
    //根据类名过滤
    boolean maches(Class clazz);
}
//方法过滤接口
public interface MethodMatcher{
    //判断是否目标方法是否需要通知
    boolean maches(Method m, Class targetClass);
    //如果maches返回true,则调用判断是静态通知还是动态通知
    public boolean isRuntime();
    //只有isRuntime返回true,则为动态通知,才会执行以下方法
    public boolean maches(Method m, Class targetClass, Object[] args);
}

    提示:尽量使用静态通知,动态通知对性能会有消耗

    3.3.2 理解Advisor:通知与切入点整合接口类

//Advisor接口
public interface PointcutAdvisor{
    //获取切入点类
    Pointcut getPointcut();
    //获取通知类
    Advice getAdvice();
}

    3.3.3 使用Spring的静态切入点

      父类:StaticMethodMatcherPointcut

      常用子类(名称映射):NameMatchMethodPointcut

        映射方法:public void setMappedName(String), public void setMappedName(String[]);

      配置NameMatchMethodPointcut类型切入点:

<beans>
    <bean id="xxx1" class="(目标实例类)"/>
    
    <bean id="xxx2" class="(通知类)"/>
    
    <!-- 定义切入点 -->
    <bean id="xxx3" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
        <!-- 定义通知切入的规则 -->
        <property name="mappedName">
            <value>order*</value>
            <!-- 不适用通配符,指定具体切入方法 
            <list>
                <value>orderxxx1</value>
                <value>orderxxx2</value>
            </list>
            -->
        </property>    
        <!-- 绑定切入点的通知 -->
        <property name="advice">
            <ref bean="xxx2" />
        </property>
    </bean>
    
    <!-- 切面代理类 -->
    <bean id="xxx4" class="org.springframework.aop.framework.ProxyFactoryBean(代理对象)">
        <property name="proxyInterfaces(目标对象实现的接口类)">
            <value>xxx.xxxxx.xxxx.xxx5</value>
        </property>
        <property name="interceptorNames(通知列表)">
            <list>
                <value>xxx3</value>
                ...
            </list>
        </property>
        <property name="target(目标对象)">
            <value>xxx1</value>
        </property>
    </bean>
</beans>

      规则表达式切入点:RegexpMethodPointcut

      配置RegexpMethodPointcut类型切入点:

<beans>
    <bean id="xxx1" class="(目标实例类)"/>
    
    <bean id="xxx2" class="(通知类)"/>
    
    <!-- 定义切入点 -->
    <bean id="xxx3" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <!-- 定义通知切入的规则 -->
        <property name="pattern">
            <!-- 定义通知切入的规则:所有类以get开头,后面至少有一个字符,接着有By,再后面至少有一个字符 -->
            <value>.*get.+By.+</value>
        </property>    
        <!-- 绑定切入点的通知 -->
        <property name="advice">
            <ref bean="xxx2" />
        </property>
    </bean>
    
    <!-- 切面代理类 -->
    <bean id="xxx4" class="org.springframework.aop.framework.ProxyFactoryBean(代理对象)">
        <property name="proxyInterfaces(目标对象实现的接口类)">
            <value>xxx.xxxxx.xxxx.xxx5</value>
        </property>
        <property name="interceptorNames(通知列表)">
            <list>
                <value>xxx3</value>
                ...
            </list>
        </property>
        <property name="target(目标对象)">
            <value>xxx1</value>
        </property>
    </bean>
</beans>

    3.3.4 动态切入点

      。。。

    3.3.5 切入点合并与交叉:通过切入点与切入点、对象、方法、等等的组合与交集形成新的切入点,创建一个实体类,编写参数切入点组合,通过属性配置bean注入切入点参数

      1.编写切入点组合工具类

//编写组合代码工具类
public class UnionPointcut implements Pointcut{
    //声明合并的Pointcut实例
    private Pointcut delegate;
    //接口方法
    public ClassFilter getClassFilter(){
        return getDelegate().getClassFilter();
    }
    public MethodMatcher getMethodMatcher(){
        return getDelegate().getMethodMatcher();
    }
    //声明异常
    private Pointcut getDelegate(){
        if(delegate == null){
            throw new AopConfigException("No pointcuts have configured.");
        }
        return delegate;
    }
    //组合切入点的逻辑代码
    public void setPointcuts(List pointcuts){
        if(pointcuts == null || pointcuts.size() == 0){
            throw new AopConfigException("Must have at least one Pointcut.");
        } 
    }
    delegate = (Pointcut)pointcuts.get(0);
    for(int i = 1; i<pointcuts.size(); i++){
        Pointcut pointcut = (Pointcut)pointcuts.get(i);
        delegate = Pointcuts.union(delegate, pointcut);
    }
}

      配置<bean id="xxx" class="xxx.xxx.UnionPointcut"><property name="pointcuts"><Lits><value>xxx</value>...</List></property></bean>

    2.编写切入点交集工具类:

      。。。

  3.4 创建引入切面:对已有的实体类添加行为或属性

    。。。

   3.5 ProxyFactoryBean详解

    常用属性:target、proxyInterfaces、interceptorNames

    

    

  3.6 自动代理:BeanNameAutoProxyCreator、DefaultAutoProxyCreator

    BeanNameAutoProxyCreator可以的代理类型:切入点、通知、拦截器,DefaultAutoProxyCreator只能代理切入点(Advisor)

    BeanNameAutoProxyCreator配置

<bean id="xxx1" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="beanNames">
        <list>
            <!-- 正则表达式 -->
            <value>*Service</value>
        </list>
    </property>
    <property name="interceptorNames">
        <value>xxx(切入点、通知、拦截器)</value>
    </property>
</bean>

    DefaultAutoProxyCreator配置:

<bean id="xxx1" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <property name="advice">
        <ref bean="xxx2(通知)">
    </property>
    <property name="pattern">
        <value>.+Service\..+</value>
    </property>
</bean>
<!-- 自动代理Advisor通知 -->
<bean id="xxx3" class="org.springframework.aop.framework.autoproxy.DefaultAutoProxyCreator"/>

  

  

    

 

posted @ 2015-12-11 11:46  chenyongsai  阅读(308)  评论(0编辑  收藏  举报