• Spring,Spring-boot(一)


    前言

    Spring作为java开源世界第一开源框架,已经成为事实上的Java EE开发标准。

    最根本的使命就是简化Java开发。

    不重复制造车轮 Don’t reinvent the wheel .从代码层面来看,就是一句话,如何更加合理的利用已有的代码,不重复创建。

    本文重点整理Spring、SpringMVC的核心功能、主要组件、用到的设计模式、及Spring-boot的使用。

    参看资料

    1、Spring源码解析

    设计理念与整体架构、容器的基本实现、默认标签的解析、自定义标签的解析、bean的加载、容器的功能扩展、AOP、数据库连接JDBC、整合Mybatis、事务、

    SpringMVC、远程服务、Spring消息服务等内容。

    2、Spring-boot实战

    3、Java EE 开发的颠覆者 Spring-boot实战

    一、Spring的基础功能

    1.1 主要模块:

    • JDBC:完成了对底层jdbc纯粹的封装。
    • Orm : 对象关系映射(Object Relational Mapping)。Spring没有主动提供支持mybatis框架的功能 (提供包),此orm模块主要支持hibernate,如果想在spring框架中使用mybatis,需要另外导包。
    • Transaction: 事务处理模块。
    • Aop: 面向切面编程,他和Aspects模块配合使用。
    • Bean: 对象 ,专门用来处理对象的实例化功能。
    • Core: spring的核心包。
    • Web,websevlet,属于控制器层的,spring框架对该曾也有支持,但是并不理想,后来由springMVC来替代。
    • Context: 上下文路径,主要功能加载配置文件,或者扫描加载项目下包。
    • spEl: spring的EL表达式。

    (1)Core Container。

    Core Container(核心容器)包含有Core、Beans、Context和Expression Language模块。
    Core和Beans模块是框架的基础部分,提供loC(转控制)和依赖注入特性。这里的基础概念是BeanFactory,它提供对Factory模式的经典实现来消除对程序性单例模式的需要,并真正地允许你从程序逻辑中分离出依赖关系和配置。

    • Core模块主要包含Spring框架基本的核心工具类,Spring的其他组件要都要使用到这个包里的类,Core模块是其他组件的基本核心。当然你也可以在自己的应用系统中使用这些工具类。
    • Beans模块是所有应用都要用到的,它包含访问配置文件、创建和管理 bean以及进行Inversion ofControl/Dependency Injection(loC/DI)操作相关的所有类。
    • Context模块构建于Core和Beans模块基础之上,提供了一种类似于JNDI注册器的框架式的对象访问方法。Context模块继承了Beans的特性,为Spring核心提供了大量扩展,添加了对国际化(例如资源绑定)、事件传播、资源加载和对Context的透明创建的支持。Context模块同时也支持J2EE的一些特性,例如EJB、JMX和基础的远程处理。ApplicationContext接口是Context模块的关键。
    • Expression Language 模块提供了一个强大的表达式语言用于在运行时查询和操纵对象。它是JSP2.1规范中定义的unifed expression language的一个扩展。该语言支持设置/获取属性的值,属性的分配,方法的调用,访问数组上下文(accessiong the context ofarrays)、容器和索引器、逻辑和算术运算符、命名变量以及从Spring的IoC容器中根据名称检索对象。它也支持 list投影、选择和一般的 list聚合。

    (2)Data Access/Integration。

    Data Access/Integration层包含有JDBC、ORM、OXM、JMS和Transaction模块,其中∶JDBC模块提供了一个JDBC抽象层,它可以消除冗长的JDBC编码和解析数据库厂商特有的错误代码。这个模块包含了Spring对JDBC数据访问进行封装的所有类。ORM模块为流行的对象-关系映射API,如JPA、JDO、Hibernate、Batis等,提供了一个交互层。利用ORM封装包,可以混合使用所有Spring提供的特性进行O/R映射。如前边提到的简单声明性事物管理。
    Springg框架插入了若干个ORM框架,从而提供了ORM的对象关系工具,其中包括JDO、Hibernate和iBatisSQLMap。所有这些都遵从 Spring的通用事务和DAO异常层次结构。

    • OXM模块提供了一个对ObjectXML映射实现的抽象层,ObjectXML映射实现包括JAXB、Castor、XMLBeans、JiBX和XStream。
    • JMS(Java Messaging Service)模块主要包含了一些制造和消费消息的特性
    • Transaction模块支持编程和声明性的事物管理,这些事物类必须实现特定的接口,并且对所有的POJO都适用。

    (3)Web。

    • Web上下文模块建立在应用程序上下文模块之上,为基于Web的应用程序提供了上下文。所以,Spring框架支持与Jakarta Struts的集成。Web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。Web层包含了Web、Web-Servlet、Web-Struts和WebPorlet模块,具体说明如下。
    • Web模块∶提供了基础的面向Web的集成特性。例如,多文件上传、使用servletlsteners初始化loC容器以及一个面向 Web的应用上下文。它还包含Spring远程支持中Web的相关部分。
    • Web-Servlet模块 web.servletjar∶该模块包含Spring的model-view-controller(MVC)实现。Spring的MVC框架使得模型范围内的代码和web forms之间能够清楚地分离开来,并与Spring 框架的其他特性集成在一起。
    • Web-Struts模块∶该模块提供了对Struts的支持,使得类在Spring应用中能够与一个典型的Struts Web层集成在一起。注意,该支持在Spring3.0中是deprecated的.
    • Web-Porlet模块∶提供了用于Portlet 环境和Web-Servlet模块的 MVC的实现。

    (4)AOP。

    • AOP模块提供了一个符合 AOP联盟标准的面向切面编程的实现,它让你可以定义例如方法拦截器和切点,从而将逻辑代码分开,降低它们之间的耦合性。利用 source-level的元数据功能,还可以将各种行为信息合并到你的代码中,这有点像Net技术中的atribute概念。

    通过配置管理特性,SpringAOP模块直接将面向切面的编程功能集成到了Spring框架中,所以可以很容易地使Spring框架管理的任何对象支持AOP。Spring AOP模块为基于Spring的应用程序中的对象提供了事务管理服务。通过使用SpringAOP,不用依赖EJB组件,就可以将声明性事务管理集成到应用程序中。

    • Aspects模块提供了对AspectUJ 的集成支持。
    • Instrumentation模块提供了classinstrumentation 支持和claslader实现,使得可以在特定的应用服务器上使用。

    (5)Test。

    Test模块支持使用JUnit和 TestNG 对 Spring 组件进行测试。

    1.2 主要功能介绍

    Spring的功效:

    • 通过xml配置文件在项目运行后,帮助程序员创建了在xml中配置标签的类对象的实例。 这样就降低了程序人员对于创建实例的关注度,而是把更多的精力放在更重要的业务逻辑功能。
    • 帮助创建对象实例
    • 帮助控制接口
    • 帮助创建业务逻辑层的实现类(serviceImpl)
    • 能不能托管servlet(不能,交给springMVC去做)

    单纯的一个spring的配置文件:就是实例化,配置bean标签,id,calss属性:IOC和DI注入。

    Spring不重复的造轮子,它的出现最大的服务的就是Service层,业务层,不再需要new对象。

    1.2.1 IOC/DI (现在都是通过注解来实现了。)

    对象控制反转 invertion objcet control/ dependency injection(依赖注入) ,用来处理类的实例化问题。

    控制: 控制类的实例化
    反转: 程序员在获取对象实例的正常过程,需要是new关键字创建实例,现在有xml配置文件帮助生成对象实例。

    1.2.1.1  对象控制反转 invertion objcet control

    实例化对象的几种方式:

    1 采用默认空参构造器创建对象(这是spring创建对象实例采用的默认的方式)
    <!-- 方式1 :通过默认的空参构造器构建对象 -->
    <bean id="peo" class="com.bjsxt.pojo.People"></bean> 
    2采用有参构造器构建对象:
    • 前提: 首先类中需要提供带参的构造器,属性的类型、名称必须与参数完全一致,使用index注入的时候,还要注意参数的顺序。
    • 使用 name value 根据参数的名称匹配对应的类的成员变量
    • 使用 index value 根据参数的下标索引匹配成员变量
    • 使用type 自动查找类的属性的类型,如果匹配完成值的注入
    • 注意事项: 对于基本数据类和String,值的注入使用value属性即可,对于引用类型 需要使用 ref属性标签
    <!--方式2: 通过带参构造器创建对象 -->
    <bean id="peo" class="com.bjsxt.pojo.People">
    <!-- 使用name 与value 的属性为成员变量通过构造器赋值 --> 
    <!-- <constructor-arg name="id" value="101"></constructor-arg>
    <constructor-arg name="name" value="张三"></constructor-arg> -->
    
    <!-- 使用index索引给属性赋值 -->
    <!-- <constructor-arg index="1" value="101"></constructor-arg>
    <constructor-arg index="0" value="张三"></constructor-arg> -->
    <!-- 通过参数的类型自动匹配注入类的成员变量 -->
    <constructor-arg type="int" value="101"></constructor-arg>
    <constructor-arg type="java.lang.String" value="张三"></constructor-arg>
    </bean>

    1.2.1.2 依赖注入 --- > dependency injection 

    总的来说,所谓依赖注入说的是类和类之间的关系。
    依赖,指一个类作为另一个类的属性。
    注入,通过外部的方式给这个属性赋值。
    本质上来说,依赖注入 就是IOC . IOC 是通过spring管理器来给类实例化,而DI是给一个类中的另一个类赋值,看问题的角度不同,一个是实例化对象,另一个是为了赋值,但是从代码角度来说,没有区别。

    类与类之间的6种关系:
    继承: 父子关系
    实现: 接口 与实现类之间的关系
    依赖: 一个类作为另一个类的方法的参数或者局部变量
    关联: 一种强烈的依赖关系,一个类作为另一个类的属性而存在
    聚合: 两个类之间存在局部与整体的关系, 就好比 主机与主板之间的关系,一个类作为另一个类的属性而存在。
    组合: 二者之间存在局部与整体的关系,就好比脑袋和人,一个类作为另一个类的属性而存在。
    从代码的角度,后三者的结构相同,但是从语义的角度来看,三者之间的紧密型排列如下:
    组合>聚合>关联>依赖
    使用依赖注入的用途:
    解决类与类之间耦合性太高的问题,比如在一个控制器中手动创建业务实体类。那么通过这种依赖注入降低耦合性,以配置的方式为类中另一个作为属性的类赋值。

    代码事例:
    创建People和Company两个类,Company作为People类的属性,具备了依赖关系,通过Di给该属性注入值

    <!-- 通过依赖注入给people类属性赋值 --> 
    <bean id="peo" class="com.bjsxt.pojo.People">
        <property name="id" value="101"></property> 
        <property name="name" value="zhangsan"></property>
        <!-- value 属性只适用于基本数据类型,String,以及date类型,如果属性为对象类型,则需要使用ref关键字来进行注入 -->
        <property name="company" ref="com"></property> 
    </bean>
    <bean id="com" class="com.bjsxt.pojo.Company">
        <property name="id" value="1011"></property>
        <property name="name" value="航空航天公司"></property>
    </bean>

    在使用属性注入的时候,需要注意:

    • 属性名称必须一致,包括大小写;
    • 在给基本类型、String类型以及Date类型注入值,可以使用value属性,但是如果属性是一个类,则需要使用ref属性,被注入的作为属性的类必须出现在spring容器中,以<bean>标签的形式创建实例对象;
    • 使用属性注入方式,注入者必须具有set、get方法。

    关于自动装配:

    • 当一个类作为无论另一类的属性时,可以通过autowire="no";autowire="byName";;autowire="byType" ;autowire=" constructor"来给该对象属性自动装配,注入值;需要注意的是:当采用通过byName与byType时,注入者必须有该对象属性的set,get方法,而采用construtor时则必须有其构造方法(不常用)。
    • 此外,无论是否注入了值,该对象都是会被实例化了的。

    参看链接:https://www.cnblogs.com/zhangshuaivole/p/13493299.html

    测试:

    //测试:
    
    类路径: 从classes文件包中查找xml配置文件,生成spring容器
    
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    
    //获取People实例
    
    People people = ac.getBean("peo", People.class);

    关于@Resource、@Autowired和default-autowire区别联系

    后面引入注解,当配置文件中引入

    <context:component-scan base-package="com.bjsxt.service.impl"></context:component-scan>

    支持注解扫描com.bjsxt.service.impl这个类,(我认为已经封装了bean形式的name和class属性)即支持注解时,@Autowired根据byName注入,注解@Resource依次byName和byType注入。而Spring还有其他的子标签。我们只是介绍了它实例化对象即配置bean(和支持注解)的配置。

    @Autowired和@Resource都可以用来装配bean,都可以写在字段上,或者方法上。
    @Autowired属于Spring的;@Resource为JSR-250标准的注释,属于J2EE的。
    @Autowired默认按类型装配,默认情况下必须要求依赖对象必须存在,如果
    要允许null值,可以设置它的required属性为false,例如:@Autowired(required=false),如果我们想使用名称装配可以结合@Qualifier注解进行使用,如下:
    @Autowired()
    @Qualifier("baseDao")
    private BaseDao baseDao;
    @Resource,默认安装名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
    例如:
    @Resource(name="baseDao")
    private BaseDao baseDao;
    推荐使用:@Resource注解在字段上,这样就不用写setter方法了,并且这个注解是属于J2EE的,减少了与spring的耦合。这样代码看起就比较优雅。

    1.2.1.3 简单工厂(实例工厂)

    <!-- 方式3: 使用简单工厂模式构建对象 -->
    <!-- <bean id="factory" class="com.bjsxt.factory.PeopleFactory"></bean>
    <bean id="peo" factory-bean="factory" factory-method="getPeople"></bean> -->

    1.2.1.4 静态工厂

    <!-- 方式4:静态工厂模式构建对象 -->
    <bean id="peo" class="com.bjsxt.factory.PeopleFactory" factory-method="getPeople"></bean>

    1.2.1.5不同数据类型的注入方式:

    
    List
    <property name="list">
        <list>
            <value>1</value>
            <value>2</value>
            <value>3</value>
            <value>4</value>
            <value>5</value>
            <value>6</value>
        </list>        
    </property>
    
    Array
    <property name="array">
        <array>
            <value>a</value>
            <value>b</value>
            <value>c</value>
            <value>d</value>
            <value>e</value>
            <value>f</value>
        </array>        
    </property>
    4.3    Map
    <property name="map">
        <map>
            <entry key="CN">
                <value>china</value>        
            </entry>
            <entry>
                <key>
                    <value>gn</value>
                </key>
                <value>Germany</value>
            </entry>
            <entry>
                <key>
                    <value>us</value>
                </key>
                <value>USA</value>
            </entry>
        </map>
    </property>
    4.4    Set(略)
    4.5    Properties
    <property name="pros">
        <props>
            <prop key=""></prop>
            <prop key=""></prop>
            <prop key=""></prop>
            <prop key=""></prop>
            <prop key=""></prop>
            <prop key=""></prop>
            <prop key=""></prop>
        </props>
    </property>

    1.2.2 AOP 

    1.2.2.1简单介绍

    定义:ASPECT ORIENTED PROGRAMMING  面向切面的编程,是Spring在自身基本的bean功能的上做的扩展。

    aspect oriented programming 面向切面的编程 ,对方法进行一系列的处理。

    AOP 切面: 就是由一系列的方法,通知,异常组成的展示面。

    所谓 面向切面就是以类中的方法作为切入点(pointcut),然后再每一个切入点的前方或者后方加入新的功能,作用就是扩展原有方法的功能。切入的执行方法就叫做通知(advice)。

    在方法前加入的功能叫做前置通知;

    在方法后加入的功能称为后置通知

    前后都补充加入功能叫做环绕通知。

    因方法执行错误报异常叫做异常通知,

    这些通知与作为切点的方法共同组成的概念叫做切面。(aspect)

    要了解Spring的AOP就必须先了解动态代理的原理,因为AOP就是基于动态代理实现的。动态代理要从 JDK本身说起。

    在JDK的java.lang.reflect包下有个Proxy类,它正是构造代理类的入口。

    看JDK的java.lang.reflect包下有个Proxy类,我们可以知道,代理的目的是调用目标方法时,可以转而执行InvocationHandler类的invoke方法,所以如何在InvocationHandler上做文章就是Spring实现AOP的关键所在。

    Spring 底层采用的是jdk的动态代理,默认不生成接口真正的实体类对象。造成的问题是,如果要执行某个接口的方法,必然要生成一个动态代理对象,此时如果要将动态代理转换真正的实体类,必然抛出动态代理转换异常$proxy。

    如何解决:

    在spring 配置文件中,添加标签

    <aop:aspectj-autoproxyproxy-target-class="true"></aop:aspectj-autoproxy>

    此标签的含义即将底层的动态代理模式由jdk转换为cglib.转换之后,无论是否转换类型,都不会再报错。注意:即使是jdk模式的动态代理,如果不发生转换,不会报错。

    proxy-target-class 的值,false为默认值,表示不转换成实体类,true正好相反。

    例子:在user(登录日志)项目中,当需要真正的实体类对象时。

    1.2.2.2四种通知的简单应用代码实例

    1、切点

    package com.bjsxt.demo;
    /**
     * 
     * 在aop看来,每一个方法都是一个切入点
     * @author Administrator
     *
     */
    public class Demo {
    
        
        public void a(){
            
            System.out.println("Demo.a()");
            
        }
        public String b(String x){
            
            System.out.println("Demo.b()");
            return x;
        }
        public void c(){
            
            System.out.println("Demo.c()");
        }
        public void d() throws Exception{
            int a = 10/0;
            /*try {
                int a = 10/0;
            } catch (Exception e) {
                // TODO Auto-generated catch block
            //    e.printStackTrace();
            }*/
            System.out.println("Demo.d()");
            
        }
        public void f(String a){
            System.out.println("Demo.f()");
            
        }
    }

    2、配置文件:

    <?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.xsd
            ">
    <bean id="demo" class="com.bjsxt.demo.Demo"></bean>        
    <bean id="demo2" class="com.bjsxt.demo.Demo2"></bean>        
    <!-- 四种通知 -->
    <bean id="myBeforeAdvice" class="com.bjsxt.demo.MyBeforeAdvice"></bean>        
    <bean id="myAfterAdvice" class="com.bjsxt.demo.MyAfterAdvice"></bean>        
    <bean id="myArroundAdvice" class="com.bjsxt.demo.MyArroundAdvice"></bean>        
    <bean id="exceptionAdvice" class="com.bjsxt.demo.ExceptionAdvice"></bean>        
    
    <aop:config>
        <!-- 针对切点a(方法)增加前、后置通知 -->
        <!-- <aop:pointcut expression="execution(* com.bjsxt.demo.Demo.a())" id="mypoint"/> -->
        <!-- <aop:pointcut expression="execution(* com.bjsxt.demo.Demo.b(..))" id="mypoint"/> -->
        <!-- <aop:pointcut expression="execution(* com.bjsxt.demo.Demo.c(..))" id="mypoint2"/> -->
        <aop:pointcut expression="execution(* com.bjsxt.demo.Demo.d(..))" id="mypoint3"/>
         <!-- 针对demo下所有的方法增加前后置通知 -->
        <!-- <aop:pointcut expression="execution(* com.bjsxt.demo.Demo.*())" id="mypoint"/> -->
          <!-- 当前bjsxt包下的所有的类的所有的方法都被通知关联 -->
        <!-- <aop:pointcut expression="execution(* com.bjsxt.demo.*.*(String))" id="mypoint"/> -->
        <!-- <aop:pointcut expression="execution(* com.bjsxt.demo.*.*(..))" id="mypoint"/> -->
        <!-- <aop:pointcut expression="execution(* com.bjsxt.*.impl.*.*())" id="mypoint"/> -->
        <!-- <aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="mypoint"/> -->
        <!-- <aop:advisor advice-ref="myAfterAdvice" pointcut-ref="mypoint"/> -->
       <!--  <aop:advisor advice-ref="myArroundAdvice" pointcut-ref="mypoint2"/> -->
        <aop:advisor advice-ref="exceptionAdvice" pointcut-ref="mypoint3"/>
         
    </aop:config>
    
            
    </beans>

    参数说明:

    外层 config配置标签,确立切点与通知之间的切面关系。

    使用pointcut标签,确定作为切点的方法,需要设置expressionid属性。

    使用aopadvisor 关联作为通知的bean标签,当切点方法执行,随之执行。需要注意,此通知必备的两个属性: advice-ref引用作为通知的类, pointcut-ref,所关联的切点的方法。

    3、通知

    前置通知:

    package com.bjsxt.demo;
    
    import java.lang.reflect.Method;
    
    import org.springframework.aop.MethodBeforeAdvice;
    
    public class MyBeforeAdvice implements MethodBeforeAdvice{
    
        @Override
        public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
            
            System.out.println(arg0.getName());
            System.out.println(arg1);
            System.out.println(arg2);
            
    //        System.out.println("MyBeforeAdvice.before()");
    //        System.out.println("前置通知执行");
            
        }
    
    }

    后置通知:

    package com.bjsxt.demo;
    
    import java.lang.reflect.Method;
    
    import org.springframework.aop.AfterReturningAdvice;
    //实现环绕通知
    public class MyAfterAdvice implements AfterReturningAdvice{
        //重写后置通知的方法
        @Override
        public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
    
            System.out.println(arg0);
            System.out.println(arg1);
            System.out.println(arg2);
            System.out.println(arg3);
    //        System.out.println("MyAfterAdvice.afterReturning()");
    //        System.out.println("后置通知执行");
        }
    
    }

    环绕通知:

    package com.bjsxt.demo;
    
    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    
    public class MyArroundAdvice implements MethodInterceptor{
    
        @Override
        public Object invoke(MethodInvocation arg0) throws Throwable {
            System.out.println("触发前置通知");
            arg0.proceed();
            System.out.println("触发后置通知");
            
            
            return null;
        }
    
    }

    异常通知:

    package com.bjsxt.demo;
    
    import org.springframework.aop.ThrowsAdvice;
    
    public class ExceptionAdvice implements ThrowsAdvice{
        
           public void afterThrowing(ArithmeticException ex) throws Throwable {
               
               System.out.println("触发了异常 ");
               System.out.println(ex.getMessage());
               
            }
    
    
    }

    4、测试

    package com.bjsxt.demo;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Test {
    
        public static void main(String[] args) {
            //ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
            ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
            Demo demo = ac.getBean("demo", Demo.class);
    //        Demo2 demo2 = ac.getBean("demo2", Demo2.class);
    //        demo.a();
    //        demo.b("haha");
    //        demo.c();
            try {
                demo.d();
            } catch (Exception e) {
                e.printStackTrace();
            }
    //        demo.f("haha");
    //        demo2.e();
            
        }
    }

    前置方法参数:(3个)

    Method arg0, 关联的切点方法

    Object[] arg1, 关联切点方法的参数列表(Object类型元素)

    Object arg2,切点方法所在的类对象

    后置通知的参数:(4个)

    arg0, 切点方法的返回值

    Method arg1, 关联的切点方法 

    Object[] arg2, 关联切点方法的参数列表(Object类型元素)

    Object arg3,切点方法所在的类对象

    环绕通知:创建环绕类,实现MethodIntercepto 接口,实现invoke方法。一般环绕通知不会和前后置通知并处,有矛盾的地方。 

    异常通知:创建异常通知: Exception Advice  ,实现ThrowsAdvice,即异常通知接口,实现了 afaterthrowing这个方法。

    作用:一旦在切面的执行过程中,切点方法出现异常,就会被异常通知对象所捕获并给予提示。

    注意: 在切点中发生的异常可以不处理,也可以向外声明,都会被异常捕获通知所获取,便于快速查找错误发生的位置。但是,千万不要在错误发生,即切点方法中自行捕获处理异常,因为这样做,异常捕获通知不会获取任何异常信息,不便于程序的调试。

    总结:前置通知+后置通知+环绕通知+异常通知+切点方法组合在一起,就行成了所谓切面AOP,aop最主要的功能就是性能的扩展。 

    1.2.2.3应用

    日志管理,拦截信息。

    1.2.2.4Spring 通过XML配置文件以及通过注解形式来AOP 来实现前置,环绕,异常通知,返回后通知,后通知

    参看链接:https://www.cnblogs.com/liuhongfeng/p/4736947.html

    1.2.3 事务

    1事务的分类

    1.1编程式事务

    例: OpenSessionInView

    程序人员将事务的处理用编码的方法手动处理提交,即所谓编程式事务。注意,不是写了代码就叫事务,该代码必须与事务直接相关联,比如commit

    或者rollback这类指令,才可以认为是编程式事务。 

    1.2声明式事务

    1.2.1Spring提供了一种强大的事务管理方案,这种方案允许变成人员只需告知哪些方法需要事务支持,不需要你手动对事务进行处理、

    1.2.2Spring的声明式事务与aop息息相关。从本质上说,spring事务就是一个通知类。他把对事务的处理封装到一个事务处理类当中,然后结合aop实现事务的管理。

    1.2.3既然与aop结合,必然涉及到切点和通知。通知就是事务的处理类,切点是谁?是service层的业务方法。 原因是业务层是纯粹的业务逻辑层,再有业务层调用持久化层的方法,大多情况下是批量执行的,多个sql语句并行,这时候,就需要事务加以强大的支持,让语句全部执行,或者全部不执行,service作为事务控制层最为合适。

    1.2.4使用事务有什么好处?

    1.2.4.1简单高效

    1.2.4.2功能强大。 

    1.2.5在项目中如何引入spring声明事务进行管理

    1.2.5.1由于事务与aop相结合,需要定义切点方法(即事务控制的方法)还有通知。

    1.2.5.2通知由spring特有的结构模式,<tx:advise></tx>规定

    <tx:advice id="tran" transaction-manager="txm" >
    
        <tx:attributes>
    
            <tx:method name="register" read-only="false"/>
    
            <tx:method name="ins*"/>
    
            <tx:method name="del*"/>
    
            <tx:method name="upd*"/>
    
            <tx:method name="*"/>
    
        </tx:attributes>
    
    </tx:advice>    

    而事务通知标签是由spring提供的事务管理类进行监控托管

    <bean id="txm" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"></bean>

    Aop 负责设置收到事务控制的切点的方法,以及相关联的具体的通知

    <aop:config>
    
        <aop:pointcut expression="execution(* com.bjsxt.service.impl.UserServiceImpl.register(..))" id="mypoint"/>
    
        <aop:advisor advice-ref="tran" pointcut-ref="mypoint"/>
    
    </aop:config>

    1.2.5.3 方法的属性:

    1.2.5.3.1Read-only: 默认值为false,表示处理事务。如果为true,则表示不处理事务,一般用于查询方法。

    1.2.5.3.2Propogation : 事务传播行为属性

    Data Type : string
    
    Default Value : REQUIRED
    
    Enumerated Values : 
    
        - REQUIRED
    
        - SUPPORTS
    
        - MANDATORY
    
        - REQUIRES_NEW
    
        - NOT_SUPPORTED
    
        - NEVER

    1.2.4 注解

    1       spring 框架本身是有注解的,比如aop就是(很少有人用)

    1.1      问题: 使用spring容器管理哪些类,就是在容器当中放置每一个类的标签,然后通过容器进行实例化,从而带到执行实现类方法的效果。但是,如果需要托管的类过多,每一个都要在容器配置文件当中存在,工作十分犯错且易出错。

    1.2      解决方式: 使用注解

    1.2.1  在需要实例化的对象(或者叫注入值的类的上面)标注

    @Component(value=”xxx”),其中value的值就是在容器中的beanid

    1.2.2  报错的原因是spring容器不会主动查找需要使用注解的类,你要告诉spring容器哪些类需要使用注解托管。

    1.2.2.1 spring配置文件中增加新的命名空间  

    xmlns:context=http://www.springframework.org/schema/context

    组件:略

     

    1.2.2.2告知spring到哪个包下寻找使用注解的类

    <context:component-scan base-package="com.bjsxt.service.impl"></context:component-scan>

     

    1.2.3  注意事项:

    1.2.3.1如果只写一个@Component 标注,也会顺利执行操作。spring会默认你的注解类的类名(首字母小写)作为在容器中bean id值、

    1.2.3.2如果注解的value值为自定义类型,则从spring获取id值的时候也必须与注解当中定义的值名称完全一致,否则无法从容器中获取gaibean (另: value= 可以省略)

    1.2.3.3注解一定标准在实现类上,能标准在接口上?肯定不行,因为接扣无法实例化对象,只有实现类可以。

    1.2.4  @Component 注解关键字并不是通常使用的注解声明,这是一个宽泛的该概念,涉及整个spring容器的注解项。对于业务逻辑层,还有一个更加贴切的注解方式,叫 @Service

    1.2.4.1service是专注于业务逻辑层的注解,在真正的注解方式中,使用几率要远大与@Component

    1.2.5  其他层的Component子注解

    1.2.5.1持久化层: @Repository  mybatis中并不使用。因为mybati s使用配置文件+接口完成dao层实现类的功能,本质是动态代理,没有实现类;Hibernate会使用到这个注解关键字。

    1.2.5.2控制器层使用: servlet  ,使用的注解 @Controller ,spring能不能用Controller 不能,springMVC使用此注解。

    1.3      关注业务逻辑层实现类,需要被注入的属性classroomMapper

    1.3.1  此属性需要提供getset方法来采用DI的方式注入值

    1.3.1.1使用@Resource : 此种方式为 jdk提供的代替getset对属性注入的注解方式,他默认采用 byName的类型进行值注入

    1.3.1.2使用@autowired :此种方式是spring容器默认提供的代替方式,他采用byType的方式进行值注入

    1.4      比较常用的注解:

    1.4.1  Value${jdbc.driver}

    Value${jdbc.driver}

    String str;

    1.4.2  @Service

    1.4.3  @Resource

    1.4.4  @Autowired

     

    二、Spring中用到的设计模式

    2.1 工厂设计模式

    2.1.1整合mybatis,mybatis中用到的设计模式

    回忆mybatis中用到的最多的设计模式就是工厂设计模式。

    mybatis就做两件事:根据JDBC规范建立与数据库的连接,通过反射打通Java对象与数据库参数交互之间相互转化的关系。

    mybatis是典型的交互式框架。

    简单工厂设计模式:DataExchangeFactory。简而言之:就是定义好产品接口,具体产品,客户调用工厂类,在工厂中生产产品。

    抽象工厂设计模式:dataSourceFactory:有多个产品接口。

    2.2代理模式

    2.2.1 静态代理

    组成:
    抽象对象 : 接口或者是父类
    被代理对象: 被隐藏起来的对象
    代理对象: 暴露在外,向外提供的对象
    调用者: 调用代理对象
    举例: 房东想要向外租房
    抽象对象; 具体要完成的事 : 租房
    被代理对象: 房东
    代理对象:中介
    调度者: 租客
    带来的好处:
    将被代理对象隐藏,保护隐私,从代码层面说,隐藏那些不必或者不应该暴露在外的类和代码。
    扩展了原有的功能的。
    使得被代理对象更加专注地完成自己的工作。
    坏处:
    如果被代理对象过多(比如生活距离,要求被代理的房东多,房源多),那么就需要构筑大量的代码进行逻辑判断,这无形中增加了代码的冗余度。

    代码示例:

    抽象对象:

    package com.bjsxt.pojo;
    
    public interface ZuFang {
        public void zuFang();
    }

    被代理对象:

    package com.bjsxt.pojo;
    
    public class FangDong implements ZuFang{
        public void zuFang(){
            System.out.println("房东出售一套西三旗的房");
        }
    }

    代理对象:

    package com.bjsxt.pojo;
    
    public class ZhongJie implements ZuFang{
        FangDong fd=new FangDong();
        public void zuFang(){
            //中介租房
            System.out.println("向房东收取介绍费");
            fd.zuFang();
            System.out.println("向租客收取介绍费");
        }
    }

    调度者:

    package com.bjsxt.pojo;
    
    public class We {
        public static void main(String[] args) {
            //静态代理
            ZhongJie zj=new ZhongJie();
            zj.zuFang();
            
            //动态代理
            FangDong fongdong = new FangDong();
            ZhongJie2 zj2=new ZhongJie2();
            zj2.setObj(fongdong);
            zj2.zuFang();
        }
        
        
    }

     上面的是静态代理,下面向动态代理转变:

    可以看出来,黄色部分的代理操作,需要采用反射,才能够实现。

    package com.bjsxt.pojo;
    
    public class ZhongJie2 implements ZuFang{
        Object obj=null;
        
        public Object getObj() {
            return obj;
        }
    
        public void setObj(Object obj) {
            this.obj = obj;
        }
    
        public void zuFang(){
            //中介租房
            System.out.println("向房东收取介绍费");
            //obj.zuFang();//需要判断是哪一个对象,才能调用方法,故而是必然用到反射的。
            //应用动态代理模式,底层采用反射的机制,得到被代理对象,并得到其,业务接口的实现类对象,方法,
            //参数,从而调用被代理对象实现业务接口的方法
            System.out.println("向租客收取介绍费");
        }
    }

    2.2.2 动态代理

    1 动态代理相对于静态代理带来的改变: 解决静态代理如果被代理类过多造成的冗余代码问题。
    2 动态代理的原理: 底层是通过反射的方式完成被代理对象方法的执行。
    3 动态代理模式:
    3.1 Jdk下的Proxy模式(讲解对象)
    3.2 Cglib (需要导包)
    4 创建动态代理项目: dynamic_proxy
    4.1 动态代理并不改变代理模式的基本架构:
    4.1.1 抽象对象
    4.1.2 被代理对象
    4.1.3 代理对象:重点修改对象
    4.1.4 调用者
    4.2 对代理对象类的修改:
    4.2.1 去掉实现租房业务的接口
    4.2.2 继承 InvocationHandler接口重写invoke 方法
    4.2.3 添加房东类(被代理对象)的get、set方法
    4.2.4 在调用者类中,调用Proxy对象的静态方法newProxyInstance(xx,xx,xx)
    4.2.4.1 三个参数的解释:
    ClassLoader loader - 定义代理类的类加载器
    Class<?>[] interfaces - 代理类要实现的接口列表 (就是你要完成的业务功能—租房)
    InvocationHandler h - 指派方法调用的调用处理程序 (谁是代理-中介)
    4.2.5 代理类(ZhongJie)实现了InvocationHandler接口,目的是实现invoke方法
    4.2.5.1 Invoke 方法的三个参数:
    4.2.5.1.1 Proxy 为抽象对象生成的临时代理对象
    4.2.5.1.2 Method: reflect包下的Method的对象,要通过反射执行某个类的方法
    4.2.5.1.3 Args: 该方法的参数
    5 动态代理带来的好处:
    5.1 扩展性增加:
    5.2 解决了被代理对象过多造成冗余代码的问题
    5.3 解耦性提高: 作为代理类的结构代码无需进行返回修改,只要根据调用者提供的代理对象及被代理对象灵活分配(底层应用了反射技术实现)

     代码示例:

    抽象对象:

    package com.bjsxt.pojo;
    
    public interface ZuFang {
        public void zuFang();
    }

    被代理对象:

    package com.bjsxt.pojo;
    
    public class FangDong implements ZuFang{
        public void zuFang(){
            System.out.println("房东出售一套西三旗的房");
        }
    }

    代理对象:

    package com.bjsxt.pojo;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class ZhongJie implements InvocationHandler{
        Object obj=null;
    
        public Object getObj() {
            return obj;
        }
    
        public void setObj(Object obj) {
            this.obj = obj;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // TODO Auto-generated method stub
            System.out.println("收介绍费");
            Object object = method.invoke(obj, args);
            System.out.println("收手续费");
            return object;
        }
        
    }

    调度者:

    package com.bjsxt.pojo;
    
    import java.lang.reflect.Proxy;
    
    public class We {
        public static void main(String[] args) {
            FangDong fd=new FangDong();
            ZhongJie zj=new ZhongJie();
            zj.setObj(fd);
            ZuFang zf = (ZuFang) Proxy.newProxyInstance(We.class.getClassLoader(), new Class[]{ZuFang.class}, zj);
            zf.zuFang();    
        }
        
        
    }

    2.3单例模式

    2.3.1 Scope模式

    Spring 对于每一个<bean>表现来说设计模式默认为单例模式,但仅限于本标签(bean标签)。如果创建多个标签,即使 指向的是同一个类,仍然会创建多个实例。

    Scope的取值与含义:

    Spring的 Bean对象默认情况下为单例模式,只会产生一个单实例,与设置scope=“singleton”等效。另外,spring容器在加载配置文件时,会把所有默认和singleton方式的bean实例化一遍,不论是否被调用。
    prototype: 每一次被调用的时候,spring容器都会创建一个新的实例,但是如果不调用,则不会创建任何实例。
    request: 当发生请求的时候产生实例
    session:当创建会话的时候产生实例
    application: 当创建的application对象的时候产生实例
    globalapplication: 略
    单例的好处:
    节省了内存空间
    在共享环境如application下可以传值

    2.4 策略模式

    2.4.1策略模式实现原理

        

    2.4.2Spring中策略模式的实现

    三、用Spring进行开发

    四、SpringMVC介绍

    4.1 SpringMVC工作原理

    参看链接:https://www.cnblogs.com/xiaoxi/p/6164383.html

    五、Spring-boot的介绍

    Spring-boot旨在简化Spring的开发。

    5.1 介绍

    六、Spring-boot的使用

    6.1 SpringBoot2.0 整合 Shiro 框架,实现用户权限管理

    参看链接:https://www.cnblogs.com/cicada-smile/p/11186513.html

    6.2 SpringBoot 教程之 banner 定制

    参看链接:https://juejin.im/post/6844903840936886280

    存储、数据库、网络、负载均衡、自动扩展等功能,你只需将你的程序交给云计算平台就可以了。你的程序可以是用不同的编程语言开发的,而使用的Docker的云计算平台就是用Docker 来实现以上功能及不同程序之间的隔离的。目前主流的软件以及非主流的软件大部分都有人将其封装成Docker镜像,我们只需下载Docker镜像,然后运行镜像就可以快速获得已做好配置可运行的软件。

    6.3 Spring-boot开发

    6.3.1 开发流程

    详见链接:https://www.cnblogs.com/szrs/p/13790574.html

    6.3.2 常见注解

    详见链接:https://www.cnblogs.com/szrs/p/13790574.html

    如果错过太阳时你流了泪,那你也要错过群星了。
    在所有的矛盾中,要优先解决主要矛盾,其他矛盾也就迎刃而解。
    不要做个笨蛋,为失去的郁郁寡欢,聪明的人,已经找到了解决问题的办法,或正在寻找。
  • 相关阅读:
    pm2日志切割
    PM2常用命令
    Linux安装nodejs
    npm 修改源地址
    nodejs 生成验证码
    shell脚本解析json文件
    mysql添加用户并赋予权限命令
    Redis 配置密码
    JavaScript也是黑客技术?
    angular和vue的对比学习之路
  • 原文地址:https://www.cnblogs.com/szrs/p/13493347.html
Copyright © 2020-2023  润新知