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

posted @ 2019-12-19 19:17  今天又瘦了嘛  阅读(240)  评论(0编辑  收藏  举报