zoukankan      html  css  js  c++  java
  • spring详情

    Spring简介: spring是一个框架,spring2003兴起的一个轻量级开发框架,由Rod Johnson

    框架的优势:分层架构(MVC   M:模型   v:视图  c:控制层)

    Spring优势:融合性强(spring相当于一个容器,一个大熔炉),IOC(控制反转,属性注入),Aop(面向切面编程,“oopAop就是oop的补充和完善)

    IOC&DI

    IOC(控制反转)DI(依赖注入):明确定义组件的接口,独立开发各个组件,然后根据组件的依赖关系组装运行;即将创建及管理对象的权利交给Spring容器。Spring是一个轻型容器(light-weight Container),其核心是Bean工厂(Bean Factory),用以构造我们所需要的M(Model)。能够让相互协作的软件组件保持松散耦合。降低了业务对象替换的复杂性,提高了组件之间的解耦。

    IOC(控制反转)

    控制:通过spring控制对象的创建

    反转:通过反射获得ApplicationContext容器,通过容器转换为类对象

    applicationContext&BeanFactory

    BeanFactory 接口

    spring原始接口.最底层的接口。针对原始接口的实现类功能较为单一

    BeanFactory接口实现类的容器.特点是每次在获得对象时才会创建对象,为了节省内存

    ApplicationContext

    每次容器启动时就会创建容器中配置的所有对象.并提供更多功能

    从类路径下加载配置文件:ClassPathXmlApplicationContext

    从硬盘绝对路径下加载配置文件:FileSystemXmlApplicationContext(d:/xxx/yyy/xxx)

    ioc配置详解

    4.1Bean

    <?xml version="1.0" encoding="UTF-8"?>

    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd ">

        <!--User对象交给spring容器管理  ,其中name任意,class为全包名

            class属性:被管理对象的完整类名

            name属性:给被管理的对象起个名字,根据该名称获得对象

                可以重复,可以使用特殊字符

            id属性:name属性一模一样

                名称不可重复,不能使用特殊字符

            结论:尽量使用name属性

        -->

        <bean name="user" class="com.jinghang.bean.User"></bean>

    </beans>

    4.2Spring创建对象的三种方式

    1.空参构造方式(最主要方式)

    <!--创建方式1:空参构造创建  -->

     <bean name="user" class="com.jinghang.bean.User"></bean>

    //1.创建容器对象,相对于src下的路径

    ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");

    工厂模式工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

    在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

    2.静态工厂(了解)

    public static User createUser() {

            System.out.println("静态工厂创建User");//表示由用户自己创建

            return new User();

        }

    <!--创建方式2:静态工厂创建方式  

            调用UserFactorycreateUser方法创建名为user2的对象,放入容器

        -->

        <bean name="user2"

            class="com.jinghang.UserFactory"  //类的全包名

            factory-method="createUser"></bean>     //类的方法

    //测试

    public void fun2() {

    ApplicationContext ac=new ClassPathXmlApplicationContext("com/jinghang/applicationContext.xml");

    //2.向容器“要”user对象

    User u=(User) ac.getBean("user2");

        }

    3.实例工厂(了解)

    public  User createUser2() {//不是静态方法

            System.out.println("实例工厂创建User");

            return new User();

        }

        <!--创建方式3:实例工厂创建

                调用UserFactory对象的createUser2方法创建名为user3的对象,放入容器

              -->

        <bean name="user3"

            factory-bean="userFactory"

            factory-method="createUser2"></bean>

        <bean name="userFactory"

            class="com.jinghang.UserFactory" ></bean>

    public void fun3() {

            ApplicationContext ac=new ClassPathXmlApplicationContext("com/jinghang/b_create/applicationContext.xml");

            //2.向容器“要”user对象

            User u=(User) ac.getBean("user3");

        }

    scope属性

    单例模式:

    单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

    这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

    注意:

    1、单例类只能有一个实例。

    2、单例类必须自己创建自己的唯一实例。

    3、单例类必须给所有其他对象提供这一实例。

    singleton(默认值):单例对象,被标识为单例的对象在spring容器中只会存在一个实例

    <bean name="user" class="com.jinghang.bean.User" scope="singleton"></bean>

    ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");

    //2.向容器“要”user对象

    User u=(User) ac.getBean("user");

    User u2=(User) ac.getBean("user");

    User u3=(User) ac.getBean("user");

    User u4=(User) ac.getBean("user");

    //3.打印user对象 会发现只有一个实例

    System.out.println(u==u3);

    System.out.println(u2==u4);

    4.3.2生命周期属性(了解)

    配置一个方法作为生命周期初始化方法.spring会在对象创建之后立即调用.

    init-method

    配置一个方法作为生命周期的销毁方法.spring容器在关闭并销毁所有容器中的对象之前调用.

    destory-method

    <bean name="user" class="com.jinghang.bean.User" scope="singleton" init-method="init" destroy-method="destroy"></bean>

    1

    //并在User中实现此方法

    public void init() {

            System.out.println("初始化");

        }

        public void destroy() {

            System.out.println("销毁");

        }

    属性注入

    set方法注入(重要)(前提是set注入之前该对象提供setter方法)

    <bean name="user" class="com.jinghang.bean.User" >

        <!--值类型注入:为User对象中名为name的属性注入tom作为值-->

        <property name="name" value="tom"></property>

        <property name="age" value="18"></property>

        <!--引用类型注入:为car属性注入下方配置的car对象   caruser中一个对象-->

        <property name="car" ref="car"></property>

      </bean>

      <!--car对象配置到容器中 -->

      <bean name="car" class="com.jinghang.bean.Car">

        <property name="name" value="兰博基尼"></property>

        <property name="color" value="黄色"></property>

    </bean>

    构造函数注入

    准备带有参数的构造

    <bean name="user2" class="com.jinghang.bean.User">

        <!-- name属性:构造函数参数名 -->

        <!-- index属性:构造函数参数索引  -->

        <!-- type属性:构造函数参数类型 -->

        <!-- 上述三个属性不必全部出现,根据情况选择即可 -->

        <constructor-arg name="name"  value="张三" index="0" type="java.lang.String"></constructor-arg>

        <constructor-arg name="car" ref="car"></constructor-arg>

    </bean>

    p名称空间注入(了解)

    <!-- p空间注入   走set方法

            1.导入p空间名称 xmlns:p="http://www.springframework.org/schema/p"

            2.使用p:属性完成注入

                |-值类型 : p:属性名=""

                |-对象类型:p:属性名-ref="bean名称"

          -->

        <bean name="user3" class="com.jinghang.bean.User"    p:name="jack" p:age="20" p:car-ref="car">  

        </bean>

    <!--car对象-->

    <!--car对象配置到容器中 -->

        <bean name="car" class="com.jinghang.bean.Car">

            <property name="name" value="兰博基尼"></property>

            <property name="color" value="黄色"></property>

        </bean>

    注入方式分为:

    set方法注入构造函数注入p名称空间注入(包含在set方法里边)、接口注入

    复杂类型注入

    数组,listmap等等

    public class CollectionBean {

        private Object[] arr;//数组类型注入

        private List list;//list/set类型注入

    private Map map;//map注入

    }

    数组

    <bean name="cb"  class="com.jinghang.c_injection.CollectionBean">

            <!-- 如果数组中只准备一个值(对象),直接使用value|ref即可 -->

            <!-- 对象中数组名为arr -->

            <!-- <property name="arr" value="Tom"></property> -->

            <property name="arr">

                <array>

                    <value>tom</value>

                    <value>jerry</value>

                    <ref bean="car"/>

                </array>

            </property>

    </bean>

    list

    <!-- 如果list中只准备一个值(对象),直接使用value|ref即可 -->

            <!-- <property name="list" value="Tom"></property> -->

            <property name="list">

                <list>

                    <value>tom</value>

                    <value>Jerry</value>

                    <ref bean="car"/>

                </list>

            </property>

    map

    <property name="map">

                <map>

                    <entry key="1" value="abc"></entry>

                    <entry key="2" value="def"></entry>

                    <entry key-ref="car" value-ref="car"></entry>

                </map>

            </property>

    AOP

    AOPAspect Oriented Programming),即面向切面编程,可以说是OOPObject Oriented Programming,面向对象编程)的补充和完善。

    OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

    1、横切关注点

    对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点。

    2、切面(aspect

    类是对物体特征的抽象,切面就是对横切关注点的抽象。

    3、连接点(joinpoint

    被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器。

    4、切入点(pointcut

    对连接点进行拦截的定义。

    5、通知(advice

    所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类。

    6、目标对象

    代理的目标对象。

    何为切面:

    例如

    Jdbc

    加载驱动

    创建连接

    ----------------------------------------------------------------------------------------

    操作数据

    -------------------------------------------------------------------------------------------

    关闭资源

    SpringAOP的支持

    SpringAOP代理由SpringIOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。Spring创建代理的规则为:

    1、默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了

    2、当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB

    AOP编程其实是很简单的事情,纵观AOP编程,程序员只需要参与三个部分:

    1、定义普通业务组件。

    2、定义切入点,一个切入点可能横切多个业务组件。

    3、定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作。

    所以进行AOP编程的关键就是定义切入点和定义增强处理,一旦定义了合适的切入点和增强处理,AOP框架将自动生成AOP代理,即:代理对象的方法=增强处理+被代理对象的方法。

    下面给出一个Spring AOP.xml文件模板,名字叫做aop.xml,之后的内容都在aop.xml上进行扩展:

    <?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"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">   
    </beans>

    基于SpringAOP简单实现

    开始讲解用Spring AOPXML实现方式,先定义一个接口:

    public interface Hello{
       void printHello();
       void doPrint();
    }

    定义两个接口实现类:

    public class HelloImp1 implements Hello{
       public void printHello()
       {
           System.out.println("我是user1");
       }
       
       public void doPrint()
       {
           System.out.println("张三");
           return ;
       }
    }

    public class HelloImpl2 implements Hello{
       public void printHello()
       {
           System.out.println("我是user2");
       }
       
       public void doPrint()
       {
           System.out.println("李四");
           return ;
       }
    }

    横切关注点,这里是打印时间:

    public class TimeHandler
    {
       public void printTime()
       {
           System.out.println("CurrentTime = " + System.currentTimeMillis());
       }
    }

    有这三个类就可以实现一个简单的Spring AOP了,看一下aop.xml的配置:

    <?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"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
           
         <bean id="helloImpl1" class="com.jinghang.HelloImpl1" />
         <bean id="helloImpl2" class="com.jinghang.HelloImpl2" />
         <bean id="timeHandler" class="com.jinghang.TimeHandler" />
           
         <aop:config>
           <aop:aspect id="time" ref="timeHandler">
              <aop:pointcut id="addAllMethod" expression="execution(* com.jinghang.HelloWorld.*(..))" />
              <aop:before method="printTime" pointcut-ref="addAllMethod" />
              <aop:after method="printTime" pointcut-ref="addAllMethod" />
           </aop:aspect>
         </aop:config>
    </beans>

    写一个main函数调用一下:

    public static void main(String[] args)
    {
       ApplicationContext ctx =
               new ClassPathXmlApplicationContext("aop.xml");
           
       HelloWorld hw1 = (HelloWorld)ctx.getBean("helloWorldImpl1");
       HelloWorld hw2 = (HelloWorld)ctx.getBean("helloWorldImpl2");
       hw1.printHelloWorld();
       System.out.println();
       hw1.doPrint();
       
       System.out.println();
       hw2.printHelloWorld();
       System.out.println();
       hw2.doPrint();
    }

    看到给Hello接口的两个实现类的所有方法都加上了代理,代理内容就是打印时间。

    基于SpringAOP使用其他细节

    1、增加一个横切关注点,打印日志,Java类为:

    public class LogHandler
    {
       public void LogBefore()
       {
           System.out.println("Log before method");
       }
       
       public void LogAfter()
       {
           System.out.println("Log after method");
       }
    }

    aop.xml配置为:

    <?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"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
           
           <bean id="helloWorldImpl1" class="com.jinghang.HelloWorldImpl1" />
           <bean id="helloWorldImpl2" class="com.jinghang.HelloWorldImpl2" />
           <bean id="timeHandler" class="com.jinghang.TimeHandler" />
           <bean id="logHandler" class="com.jinghang.LogHandler" />
           
           <aop:config>
               <aop:aspect id="time" ref="timeHandler" order="1">
                   <aop:pointcut id="addTime" expression="execution(* com.jinghang.HelloWorld.*(..))" />
                   <aop:before method="printTime" pointcut-ref="addTime" />
                   <aop:after method="printTime" pointcut-ref="addTime" />
               </aop:aspect>
               <aop:aspect id="log" ref="logHandler" order="2">
                   <aop:pointcut id="printLog" expression="execution(* com.jinghang.HelloWorld.*(..))" />
                   <aop:before method="LogBefore" pointcut-ref="printLog" />
                   <aop:after method="LogAfter" pointcut-ref="printLog" />
               </aop:aspect>
           </aop:config>
    </beans>

    要想让logHandlertimeHandler前使用有两个办法:

    1aspect里面有一个order属性,order属性的数字就是横切关注点的顺序

    2)把logHandler定义在timeHandler前面,Spring默认以aspect的定义顺序作为织入顺序

    2、我只想织入接口中的某些方法

    修改一下pointcutexpression就好了:

    <?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"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
           
           <bean id="helloWorldImpl1" class="com.jinghang.HelloWorldImpl1" />
           <bean id="helloWorldImpl2" class="com.jinghang.HelloWorldImpl2" />
           <bean id="timeHandler" class="com.jinghang.TimeHandler" />
           <bean id="logHandler" class="com.jinghang.LogHandler" />
           
           <aop:config>
               <aop:aspect id="time" ref="timeHandler" order="1">
                   <aop:pointcut id="addTime" expression="execution(* com.jinghang.HelloWorld.print*(..))" />
                   <aop:before method="printTime" pointcut-ref="addTime" />
                   <aop:after method="printTime" pointcut-ref="addTime" />
               </aop:aspect>
               <aop:aspect id="log" ref="logHandler" order="2">
                   <aop:pointcut id="printLog" expression="execution(* com.jinghang.HelloWorld.do*(..))" />
                   <aop:before method="LogBefore" pointcut-ref="printLog" />
                   <aop:after method="LogAfter" pointcut-ref="printLog" />
               </aop:aspect>
           </aop:config>
    </beans>

    表示timeHandler只会织入HelloWorld接口print开头的方法,logHandler只会织入HelloWorld接口do开头的方法。

    3、强制使用CGLIB生成代理

    前面说过Spring使用动态代理或是CGLIB生成代理是有规则的,高版本的Spring会自动选择是使用动态代理还是CGLIB生成代理内容,当然我们也可以强制使用CGLIB生成代理,那就是里面有一个"proxy-target-class"属性,这个属性值如果被设置为true,那么基于类的代理将起作用,如果proxy-target-class被设置为false或者这个属性被省略,那么基于接口的代理将起作用。

    Spring注解

    @Autowired或者(  @Autowired(required=false)

    @Resource(这个注解属于J2EE的)

    @ Controller

    @Service

    @Configration

    @Qualifier

    @RequestParam

    @RequestBody

    @ModelAttribute

  • 相关阅读:
    fescar源码解析系列(一)之启动详解
    dubbo源码解析二 invoker链
    dubbo源码解析一
    CSP-S 2021 游记
    使用SpEL记录操作日志的详细信息
    Router 重定向和别名是什么?
    vue项目做seo(prerender-spa-plugin预渲染)
    vue3.0初体验有哪些实用新功能
    uniapp弹窗踩坑
    Spring boot application.properties 配置
  • 原文地址:https://www.cnblogs.com/liqian-/p/12069630.html
Copyright © 2011-2022 走看看