• Eclipse/JavaWeb (三)三大框架之Spring框架 持续更新中...


    (一)发展历史

    现在我们有三个层了,可是每层之间的调用是怎样的呢?比如显示层的struts需要调用一个业务类,就需要new一个业务类出来,然后使用;业务层需要调用持久层的类,也需要new一个持久层类出来用。通过这种new方式互相调用就是软件开发中最糟糕设计的体现。简单地说,就是调用者依赖被调用者,它们之间形成了强耦合,如果我想在其他地方复用某个类,则这个类依赖的其他类也需要包含。程序就变得很混乱,每个类互相依赖互相调用,复用度极低。如果一个类做了修改,则其他的类也会受到牵连。这时就出现了spring框架。

    Spring的作用就是解耦类之间的依赖关系,一个类如果要依赖什么,那就是一个接口。至于如何实现这个接口,这就不重要了。只要拿到一个实现了这个接口的类,就可以轻松的通过xml配置文件把实现类注射到调用接口的那个类里。所有类之间的这种依赖关系就完全通过配置文件的方式替代了。所以,Spring框架最核心的就是所谓的依赖注射和控制反转。

    现在的结构是,sturts负责显示层,hibernate负责持久层,spring负责中间的业务层,这个结构是目前国内最流行的javaweb应用程序架构了。另外,由于Spring使用的依赖注射以及AOP(面向方面编程)。所以它的这种内部模式非常优秀,以至于spring自己也实现了一个使用依赖注射的MVC框架,叫做spring MVC,同时为了很好的处理事物,spring集成了hibernate,使事物管理从hibernate的持久层提升到了业务层,使用更加方便和强大。

    (二)理解IOC、DI、AOP的概念

    Spring核心

    IoC: 控制反转,解决程序对象紧密耦合问题(工厂+反射+配置文件),将程序中原来构造对象的权限,交给IoC容器来构造,当程序需要对象时,找IoC容器获取。

    AOP:面向切面编程

    DI:依赖注入,IoC容器需要为程序提供依赖对象,返回对象一同可以提供(servlet需要service,找IoC容器获取service,service由容器提供,service依赖DAO注入到service中)

    附一个简单的小例子:

    在eclipse中new一个java project

    然后导入需要的jar包:下载地址为:http://download.csdn.net/detail/u014607184/9589548

    然后在src目录下新建package,这里命名为:com.myspring,再在包下新建java文件HelloWorld和MainApp。代码如下:

    1. HelloWorld.java如下:
    package com.myspring;
    
    public class HelloWorld {
    	private String message;
        //依赖注入 public void setMessage(String message) { this.message=message; } public void getMessage() { System.out.println("Your Message :"+message); } }

         2. MainApp.java如下:

    package com.myspring;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MainApp {
    	public static void main(String[] args)
    	{//从IoC容器获得对象
         //1、获取IoC容器工厂对象 ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
         //2、从IoC容器工厂获取需要对象(根据bean的id获取) HelloWorld obj =(HelloWorld) context.getBean("helloWorld"); obj.getMessage(); } }

    这里需要注意理解的是:

    在程序中通过ApplicationContext接口,获取Spring工厂对象。

    1.ClassPathXmlApplicationContext读取src下的配置文件

    2.FileSystemXmlApplicationContext读取WEB-INF下的配置文件

    ApplicationContext是BeanFactory子接口,BeanFactory才是Spring框架最核心工厂接口。

    ApplicationContext是对BeanFactory接口扩展,企业开发很少直接使用BeanFactory。

    ApplicationContext会在容器初始化时,对其中管理Bean对象进行创建,BeanFactory会在对象获取时才进行初始化。

         3. IoC容器装配Bean(xml配置)

    方式一:使用类构造器实例化对象

    在src目录下创建beans.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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
        <bean id="helloWorld" class="com.myspring.HelloWorld">
        	<property name="message" value="Hello World!" />
        </bean>
     </beans>
    

    方式二:使用静态工厂静态方法,对对象实例化

    <bean id="bean2" class="cn.itcast.spring.b_instance.Bean2Factory" factory-method="getBean2" />

    方式三:使用实例工厂实例方法对对象实例化

    先实例化工厂:<bean id="bean3Factory" class="cn.itcast.spring.b_instance.Bean3Factory" />

    再通过工厂对象的实例方法,构造目标对象: <bean id="bean3" factory-bean="bean3Factory" factory-method="getBean3" />

    应用场景:大多数情况,可以通过构造器直接实例化,只有在对象构造过程非常复杂的情况下,才会采用工厂实例化的方式。

    这里趁热打铁把bean的相关深入一下:

    bean的作用域

    最常用的singleton和prototype两种

    singleton(单例):在一个BeanFactory对象中,引用唯一的一个目标实例

    prototype(多例):每次通过工厂执行getBean时,返回不同实例对象

    request(请求范围):创建对象保存在request范围,如果request销毁,对象销毁

    session(会话范围):创建对象保存在session中,如果session销毁,对象销毁

    * globalSession (全局会话 ) :分布式系统,全局会话的概念, 一次登录,应用多个系统

     <!-- 通过scope属性,指定bean作用域 (默认作用域 singleton) -->
        <bean id="singletonBean" class="cn.itcast.spring.c_scope.SingletonBean" /><!-- 单例 -->
        <bean id="prototypeBean" class="cn.itcast.spring.c_scope.PrototypeBean" scope="prototype"/> <!-- 多例 -->
    

    单例bean在容器初始化时,实例化(只实例化一次)

    多例bean在工程执行getbean时,才会实例化(每实例化一次,返回不同对象)

    bean的生命周期

    可以通过init-method属性配置bean对象初始化执行方法,destory-method属性配置bean对象销毁的方法(初始化方法和构造方法的区别:构造方法作用申请空间,为对象基本属性初始化;初始化方法,对象复杂构造过程,java语言建议将对象复杂构造过程单独抽取)

    public class LifeCycleBean implements IHello {
        public LifeCycleBean() {
            System.out.println("LifeCycleBean 构造...");
        }
    
        public void setup() {
            System.out.println("LifeCycleBean 初始化...");
        }
    
        public void teardown() {
            System.out.println("LifeCycleBean 销毁...");
        }
    
        @Override
        public void sayHello() {
            System.out.println("hello ,itcast...");
        }
    }
    

      

    <bean id="lifeCycleBean" class="cn.itcast.spring.d_lifecycle.LifeCycleBean" 
            init-method="setup" destroy-method="teardown" />
    

    bean的依赖注入

    1. 构造参数的属性注入
    public class Car {
        private String name;
        private double price;
    
        // 为Car类 提供构造方法
        public Car(String name, double price) {
            super();
            this.name = name;
            this.price = price;
        }
    

     通过constructor-arg属性进行构造参数注入

    <!-- 构造方法属性注入 -->
        <bean id="car" class="cn.itcast.spring.e_di.Car">
            <!-- 通过constructor-arg 注入构造函数的参数 -->
            <!-- index 代表参数顺序 ,第一个参数 0
                 type 代表参数类型 
                 name 代表参数的名称 
                 value 注入参数的值
                 ref  引用另一个bean元素的id
             -->
            <constructor-arg index="0" type="java.lang.String" value="宝马"/>
            <constructor-arg index="1" type="double" value="1000000"/>
        </bean>

          2. setter方法属性注入

    public class Employee {
        private int id;
        private String name;
    
        private Car car;// 复杂元素
    
        public void setId(int id) {
            this.id = id;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setCar(Car car) {
            this.car = car;
        }
    

      在配置文件 使用 元素完成setter属性注入

    <!-- setter方法属性注入 -->
        <bean id="employee" class="cn.itcast.spring.e_di.Employee" >
            <!-- 通过property 注入setter方法属性 (属性名称, 由setter方法推理获得)-->
            <!-- 
                name 属性名称 (由setter方法获得)
                value 注入参数的值
                ref 引用另一个Bean元素的id
             -->
            <property name="id" value="100001" />
            <property name="name" value="张三" />
            <!-- 注入复杂对象 -->
            <property name="car" ref="car" />
        </bean>
    

      [注意1]:p名称空间的使用

    p名称空间,在spring2.5版本后引入,为了简化属性依赖注入(setter方法)

    首先,在配置文件,引入p名称空间

    xmlns:p="http://www.springframework.org/schema/p"

    其次,简化setter方法注入配置

    <!-- 使用p命名空间注入 -->
        <bean id="employee2" class="cn.itcast.spring.e_di.Employee" 
            p:eid="100002" p:name="李四" p:car-ref="car"/>
    

      [注意2]:spEL表达式的使用

    在spring3.0之后,引入spEL 表达式语言,简化属性注入 
    参考 “Spring_表达式语言.pdf” 学习 
    语法: #{表达式} 
    用法一: 直接通过value注入,引用一个Bean对象 
    用法二: 引用一个Bean对象属性 
    用法三: 直接调用对象的方法

    public class ValueBean {
        private int id = 10003;
        private String name = "jor";
    
        public int getId() {
            return id;
        }
    
        public String pickName() {
            return name;
        }
    }
    

      

    <!-- spEL使用 -->
        <bean id="valueBean" class="cn.itcast.spring.e_di.ValueBean" />
        <bean id="employee3" class="cn.itcast.spring.e_di.Employee" >
            <!-- 调用valueBean的getId -->
            <property name="eid" value="#{valueBean.id}" />
            <!-- 直接调用对象的方法 -->
            <property name="name" value="#{valueBean.pickName().toUpperCase()}" />
            <!-- #{car} 效果类似 ref  -->
            <property name="car" value="#{car}" />
        </bean>
    

      

          3. 集合元素类型属性注入

         spring为每种结合都提供一个元素标签进行注入

    public class CollectionBean {
        private List<String> list;
        private Set<Integer> set;
        private Map<String, Integer> map;
        private Properties properties;
    
        public void setList(List<String> list) {
            this.list = list;
        }
    
        public void setSet(Set<Integer> set) {
            this.set = set;
        }
    
        public void setMap(Map<String, Integer> map) {
            this.map = map;
        }
    
        public void setProperties(Properties properties) {
            this.properties = properties;
        }
    

      

    <!-- 集合类型属性注入 -->
        <bean id="collectionBean" class="cn.itcast.spring.e_di.CollectionBean">
            <!-- 
                array 注入数组
                list 注入List集合
                set 注入Set集合
                map 注入Map集合
                props 注入 Properties 集合
             -->
            <property name="list">
                <list>
                    <!-- 
                        value 注入基本数据类型, String 类型
                        ref 注入引用Bean的id
                     -->
                     <value>aaa</value>
                     <value>bbb</value>
                     <value>ccc</value>
                </list>
            </property>
            <property name="set">
                <set>
                    <value>10</value>
                    <value>10</value>
                    <value>20</value>
                </set>
            </property>
            <property name="map">
                <map>
                    <!-- map中每个元素都是键值对 -->
                    <entry key="abc" value="10"></entry>
                    <entry key="def" value="20"></entry>
                </map>
            </property>
            <property name="properties">
                <props>
                    <prop key="qwe123">asd456</prop>
                    <prop key="tyu567">hjk789</prop>
                </props>
            </property>
        </bean>
    

      

  • 相关阅读:
    Shell学习笔记 ——第一天
    Myclipse 安装 Maven遇见的N个异常
    Myeclipse 创建 Web Maven项目
    Guava API
    String 转Map(基于Guava类库)
    Mybatis——helloWorld级程序
    redis
    listener、context、filter、servlet及其加载顺序
    junit 单元测试
    hibernate —— 树状存储
  • 原文地址:https://www.cnblogs.com/tinmh/p/6148558.html
Copyright © 2020-2023  润新知