• 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"/>

      

      

        

  • 相关阅读:
    樊登读书 认知天性
    【笔记】Tapable源码解析图以及webpack怎样实现一个插件plugin
    web前端使用mcg-helper代码生成工具学习笔记
    博客记录
    15ISK 驱动 BIOS等
    蒙特卡洛方法和蒙特卡洛树搜索
    求最大k个数
    求阶乘的位数和后缀0个数
    五分钟看懂一致性哈希算法
    Windows下查看GPU(NVIDIA)使用情况
  • 原文地址:https://www.cnblogs.com/chenyongsai/p/4977049.html
Copyright © 2020-2023  润新知