程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> spring入門(一),spring入門(

spring入門(一),spring入門(

編輯:JAVA綜合教程

spring入門(一),spring入門(


前面介紹了spring環境的搭建,在搭建spring環境的時候分為java環境和javaWeb環境,在javaWeb環境下通常會結合springMVC使用,在java項目中只需要把spring的包導入工程中,一般初學者會把所有的包全部導入,然後就可以通過獲得applicationContext,把類的實例化交給spring管理,然後從spring容器中獲得類的實例。

spring中有控制反轉(Ioc)和依賴注入(DI)兩個概念,Ioc和DI是spring的核心概念,同時也是一種新的編程思想。

控制反轉(Ioc)

控制反轉,顧名思義就是控制權的改變,在沒有接觸spring之前,我們要使用一個類的實例,必須使用new的方式生成一個對象,這個過程的主動權掌握在程序員亦自己寫的程序中,但是使用了spring之後,實例的創建不再由程序員手動實現,而是由spring容器來完成,實現了控制的反轉,即主動權交給了spring的IOC容器。

依賴注入(DI)

一個類包括屬性和方法,在創建了實例對象之後,或者在創建實例對象的同時,需要初始化成員變量(屬性),在spring之前成員變量的初始化可以通過構造方法或setXXX方法;在spring出現之後,由於實例的創建交給了spring的IOC容器,那麼成員變量的初始化也依賴於IOC容器,由容器去注入成員變量的值。

上面介紹了IOC和DI兩個概念,可以得出IOC和DI其實是在做一件事,就是spring的IOC容器創建實例對象,一切對象的實例化都交給了spring容器,在程序中不必手動使用new的方式實例化變量。

spring提供兩種不同的方式來配置spring,一種是配置文件(XML),另一種是基於注解(Annotation)。下面針對IOC和DI使用兩種方式一一做介紹

在介紹之前必須了解如何在java項目中獲得spring容器,也即ApplicationContext。

ClassPathXmlApplicationContext cpac=new ClassPathXmlApplicationContext("classpath:applications.xml");

獲取ApplicationContext的方式有三種,這裡使用的ClassPathXmlApplicationContext,ClassPathApplicationContext是ApplicationContext的子類,這裡的cpac就是spring的IOC容器,通過它的getBean()方法可以獲得容器中已經初始化的實例。
配置文件(XML)

假如我們有下面的學生類(student)

package com.cn.study.day1;

public class Student {
    private String id;
    private String name;
    private String age;

    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAge() {
        return age;
    }
    public void setAge(String age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
    }
//在有了有參的構造函數,必須要提供一個無參構造
    public Student(String id, String name) {
        this.id = id;
        this.name = name;
    }
//無參構造
    public Student() {

    }
    
    public void init(){
        System.out.println("我正在初始化!");
    }
    public void destroy(){
        System.out.println("我將要被銷毀了,。再見!");
    }
}

此類有三個屬性id、name、age,下面通過配置文件的方式,在spring的配置文件中配置,

<bean id="student" class="com.cn.study.day1.Student">
        <property name="id" value="1"></property>
        <property name="name" value="測試"></property>
        <property name="age" value="23"></property>
    </bean>

在spring的配置文件中配置<bean>標簽,id屬性在配置文件中必須唯一,class屬性指定類的權限類名,下面有<property>標簽,指定Student的三個屬性,且指定了屬性值,測試結果如下,

Student [id=1, name=測試, age=23]

這裡可以看到輸出了配置的值,這種方式是使用屬性注入的方式,要求必須有setXXX方法,還有另外一種方式,通過構造方法的方式注入,

<!--構造方法注入-->
    <bean id="student2" class="com.cn.study.day1.Student" init-method="init" destroy-method="destroy">
        <constructor-arg name="id" value="2"></constructor-arg>
        <constructor-arg name="name" value="test2"></constructor-arg>    
    </bean>

既然是通過構造方法的方式注入,那麼在Student類中必須要有這個構造方法,在上面的Student類中已經有了有參的構造方法,我們知道在自定義了有參的構造方法之後,系統不會再默認的提供無參構造,我們還必須添加無參構造,下面看測試結果,

Student [id=2, name=test2, age=null]

由於我們只注入了id、name兩個屬性,這裡可以打印出,age由於未賦值且其類型為String,則默認為null。

上面是通過配置文件的方式,配置了根據屬性、構造方法注入的方式,這個例子是比較簡單的,下面看一個復雜的例子,在程序中經常會采用分層、面向接口編程的思緒,

DAO接口

package com.cn.study.day1.inter;

public interface dbDAO {

    //一個簡單的dao層的保存接口
    public void save(String str);    
}

service接口

package com.cn.study.day1.inter;

public interface ServiceInter {

    /**
     * service層的保存方法
     */
    public void save(String str);
}

DAO實現類

package com.cn.study.day1.inter.impl;

import com.cn.study.day1.inter.dbDAO;

public class DbDAOImpl implements dbDAO {

    @Override
    public void save(String str) {
        // TODO Auto-generated method stub

        System.out.println(str+",我會執行數據插入操作!你會嗎?");
    }

}

service實現類

package com.cn.study.day1.inter.impl;

import com.cn.study.day1.inter.ServiceInter;
import com.cn.study.day1.inter.dbDAO;

public class ServiceImpl implements ServiceInter {
    //DAO接口對象
    private dbDAO dbDAO;
    //setXXX方法
    public void setDbDAO(dbDAO dbDAO) {
        this.dbDAO = dbDAO;
    }
    @Override
    public void save(String str) {
        // TODO Auto-generated method stub
        if(str!=null&&!"".equals(str)){
            dbDAO.save(str);
            System.out.println("執行完了DAO層的方法,我是service層的方法!");
        }
    }
}

在service的實現類中有一個DAO層的接口對象,我們下面看這種是如何根據屬性注入的,

<!--下面是一個復雜的屬性注入的例子-->
    <bean id="dbDao" class="com.cn.study.day1.inter.impl.DbDAOImpl"></bean>
    <!--下面的這個類,有一個dbDAO的屬性,需要進行屬性注入,必須提供一個set方法-->
    <bean id="service" class="com.cn.study.day1.inter.impl.ServiceImpl">
        <property name="dbDAO" ref="dbDao"></property>
    </bean>

首先,配置DAO層的bean,這裡的class屬性必須配置其實現類,然後配置service的實現類,在ServiceImpl中有一個dbDAO類型的屬性,使用ref屬性引用上面的bean。測試結果如下,

我是測試方法,我會執行數據插入操作!你會嗎?
執行完了DAO層的方法,我是service層的方法!


ref屬性可以引用spring配置文件中的bean,使用id的值。

通過上面的介紹,可以知道使用配置文件這種方式可以很方便的配置,但是當需要配置的類很多,且依賴很多的情況下,這種方式會很繁瑣,那麼另外一種方式便派上了用場。

注解(Annotation)

spring提供@Component、@Repository、@Controller、@Service四種注解,其實,只使用@Component一個便可以做到,@Repository、@Controller、@Service只是針對不同的層設置的,可以更加明顯,@Repository對應DAO層,@Controller對應控制層,@Service對應服務層,使用這三個注解可以明顯的分層,使系統容易理解,也可以只使用@Component。

使用了注解需要開啟組件自動掃描機制,在spring的配置文件中開啟組件自動掃描機制,需要context命名空間的支持,下面是一個配置文件的例子,

<?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"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"
    
    >
    <!--spring 自動檢測-->
    <context:component-scan base-package="com.cn.study.day1" />
</beans>

在spring配置文件的頭部添加context命名空間的支持,然後使用<context:component-scan base-package="">標簽開啟組件掃描,base-package屬性指定掃描的基包,此包及此包下的子包都會進行掃描。開啟了組件掃描之後,還需要自動注入,網上有說需要:<context:annotation-config/>,其實前面的組件掃描已經包含了此標簽的作用,為此不需要配置此標簽了,自動注入默認根據類型(byType)進行注入,還有根據名字注入(byName)即bean中id的值,還有根據構造方法注入(constructor)。自動注入需要@Aotuwired注解,此注解可以放在屬性上,也可以放在setXXX方法上,放在屬性上則可以省略setXXX方法,下面是具體的例子

package com.cn.study.day1;

import org.springframework.stereotype.Component;

@Component("su")
public class StudentAnnotation {

    public void print(){
        System.out.println("我是使用注解生成的類!");
    }
}

在類上使用@Component注解,且指定了實例的名為su,如果不指定則默認為類名稱首字母小寫,即studentAnnotation。

下面是一個自動掃描和自動注入的例子,

package com.cn.study.day1.inter.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.cn.study.day1.inter.ServiceInter;
import com.cn.study.day1.inter.dbDAO;
@Service
public class ServiceImpl implements ServiceInter {
    //DAO接口對象
    @Autowired
    private dbDAO dbDAO;
    //setXXX方法
    public void setDbDAO(dbDAO dbDAO) {
        this.dbDAO = dbDAO;
    }
    @Override
    public void save(String str) {
        // TODO Auto-generated method stub
        if(str!=null&&!"".equals(str)){
            dbDAO.save(str);
            System.out.println("執行完了DAO層的方法,我是service層的方法!");
        }
    }
}

類上使用了@Service注解,屬性上使用了@Autowired注解,這時setDbDAO()方法可以不要。@Autowired注解就是為了省略setXXX方法的,@Autowired注解默認使用的按照類型注入,如果存在多個相同類型的實例,這裡自動注入會失敗,為了可以正確注入,引入另外一個注解@Qualifier(value=""),此注解的value屬性可以指定一個bean的id值,做到自動注入。
@Qualifier可以用在屬性或者setXXX方法上。

綜上,通過配置文件和注解兩種方式介紹了依賴注入。

有不正之處歡迎指出,謝謝。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved