Spring使用註解配置依賴注入

大部分狀況下,使用Spring配置依賴注入時,都是使用註解來進行配置,由於註解比xml要方便和簡單。不過相似於數據源對象這種配置信息容易變動的對象除外,這種對象使用xml文件來進行配置會更適合,方便於在外部進行修改,而不須要打開代碼來進行修改。java

接下來簡單介紹一下註解的配置方式,首先要讓Spring支持註解,編輯Spring配置文件內容以下:mysql

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

    <!-- 讓spring支持註解 -->
    <context:annotation-config/>
    <!-- 指定哪些包下的類受可讓Spring經過註解來管理 -->
    <context:component-scan base-package="org.zero01"/>

</beans>

經過註解配置來讓Spring幫咱們建立對象,Student類代碼以下:spring

package org.zero01;

import org.springframework.stereotype.Component;

// 加上這個註解表示該類受到Spring的管理,註解的值爲該類的id,該註解的做用至關於xml中的bean標籤
@Component("stu")
public class Student {
        ...

測試代碼:sql

package org.zero01;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

    public static void main(String[] args) {

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

        // 一樣的經過配置的id得到實例對象
        Student stu1 = (Student) app.getBean("stu");
        Student stu2 = (Student) app.getBean("stu");

        // 默認都是單例對象
        if (stu1 == stu2) {
            System.out.println("單例對象");
        }else{
            System.out.println("非單例對象");
        }
    }
}

運行結果:json

單例對象

使用註解時能夠不配置id值,直接寫上 @Component 也行:bash

package org.zero01;

import org.springframework.stereotype.Component;

@Component
public class Student {
        ...

而後經過該類的class來獲取實例對象:app

Student stu1 = app.getBean(Student.class);

可是這種方式的靈活性沒有使用id值的方式好,由於字符串是能夠經過變量改變的,而這種使用class的方式至關因而寫死在代碼上了。ide

若是不但願從容器裏取出來的不是單例對象的話,可使用 @Scope 註解來配置指定使用原型模式,須要配置屬性的值可使用 @Value 註解進行配置,例如:測試

package org.zero01;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.context.annotation.Scope;

@Component("stu")
@Scope(value = "prototype") // 取值與xml中的scope屬性是同樣的
public class Student {

    @Value("小明")
    private String name;
    @Value("15")
    private int age;
    @Value("南京")
    private String address;
    ...

測試代碼:ui

package org.zero01;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

    public static void main(String[] args) {

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

        Student stu1 = app.getBean(Student.class);
        Student stu2 = app.getBean(Student.class);

        if (stu1 == stu2) {
            System.out.println("單例對象");
        }else{
            System.out.println("非單例對象");
        }

        System.out.println(stu1.getName());
        System.out.println(stu1.getAge());
        System.out.println(stu1.getAddress());
    }
}

運行結果:

非單例對象
小明
15
南京

注:咱們能夠將 @Value 註解寫在屬性的setter方法上,和寫在屬性上的做用是同樣的。

若是須要注入自建類型,有兩個註解能夠作到,分別是 @Resource 和 @Autowired,可是要想經過這兩個註解來配置依賴注入,被注入的對象須要寫上 @Component 註解:

package org.zero01;

import org.springframework.stereotype.Component;

@Component("phone")
public class Phone {
}

package org.zero01;

import org.springframework.stereotype.Component;

@Component("dog")
public class Dog {
}

而後纔可使用 @Resource 和 @Autowired 註解配置依賴注入,Student類代碼:

package org.zero01;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.context.annotation.Scope;

import javax.annotation.Resource;

@Component("stu")
@Scope(value = "prototype")
public class Student {

    @Value("小明")
    private String name;
    @Value("15")
    private int age;
    @Value("南京")
    private String address;
    @Resource
    private Dog dog;
    @Autowired
    private Phone phone;
    ...

測試代碼:

package org.zero01;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

    public static void main(String[] args) {

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

        Student stu1 = app.getBean(Student.class);

        System.out.println(stu1.getName());
        System.out.println(stu1.getAge());
        System.out.println(stu1.getAddress());
        System.out.println(stu1.getDog());
        System.out.println(stu1.getPhone());
    }
}

運行結果:

小明
15
南京
org.zero01.Dog@47db50c5
org.zero01.Phone@5c072e3f

@Autowired 和 @Resource的區別簡述:

  • 用途:作bean的注入時使用
  • 歷史:@Autowired 屬於Spring的註解,@Resource 不屬於Spring的註解,是JDK1.6支持的註解
  • 共同點:裝配bean. 寫在字段上,或寫在setter方法
  • 不一樣點:
    • @Autowired 默認按類型裝配,依賴對象必須存在,若是要容許null值,能夠設置它的required屬性爲false,例如:@Autowired(required=false),也可使用名稱裝配,配合 @Qualifier 註解。
    • @Resource 是JDK1.6支持的註解,默認按照名稱進行裝配,名稱能夠經過name屬性進行指定,若是沒有指定name屬性,當註解寫在字段上時,默認取字段名,按照名稱查找,若是註解寫在setter方法上默認取屬性名進行裝配。當找不到與名稱匹配的bean時才按照類型進行裝配。可是須要注意的是,若是name屬性一旦指定,就只會按照名稱進行裝配。
  • 便利程度:二者的便利程度都差很少,均可以實現自動裝配
  • 耦合問題:可能會有人說使用Java自帶的 @Resource 能夠下降與Spring的耦合,但實際上註解處理器咱們使用的是Spring提供的,是同樣的,無所謂解耦不解耦的說法

使用以上介紹到的註解作一個簡單的增刪查改小例題:

pom.xml文件配置以下:

<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.14.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.39</version>
        </dependency>
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
            <version>20160810</version>
        </dependency>
    </dependencies>

Spring配置文件內容以下:

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

    <!-- 讓spring支持註解 -->
    <context:annotation-config/>
    <!-- 指定哪些包下的類受可讓Spring經過註解來管理 -->
    <context:component-scan base-package="org.zero01"/>

    <!-- 配置數據源對象 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
          p:driverClass="com.mysql.jdbc.Driver"
          p:jdbcUrl="jdbc:mysql:///school"
          p:user="root"
          p:password="your_password"
          p:maxPoolSize="10"
          p:minPoolSize="1"
          p:loginTimeout="2000"
    />

</beans>

首先是接口代碼:

package org.zero01.dao;

import org.zero01.pojo.Student;

import java.util.List;

public interface DAO {

    public int insert(Student student) throws Exception;
    public int delete(int sid) throws Exception;
    public List<Student> selectAll() throws Exception;
    public int update(Student student) throws Exception;
}

package org.zero01.service;

import org.zero01.pojo.Student;

import java.util.List;

public interface Service {

    public int enterSchool(Student student);
    public int dropOut(int sid);
    public List<Student> getStudents();
    public int updateData(Student student);

}

package org.zero01.view;

import org.zero01.pojo.Student;

import java.util.List;

public interface View {

    public int enterSchool(Student student);
    public int dropOut(int sid);
    public List<Student> getStudents();
    public int updateData(Student student);
}

而後是具體的實現類代碼,StudentDAO類:

package org.zero01.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.zero01.pojo.Student;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

@Component("stuDAO")
public class StudentDAO implements DAO {

    @Autowired
    private DataSource dataSource;

    public int insert(Student student) throws Exception {

        Connection connection = null;

        try {

            connection = dataSource.getConnection();
            String sql = "INSERT INTO student(sname,age,sex,address) VALUES (?,?,?,?)";
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, student.getSname());
            preparedStatement.setInt(2, student.getAge());
            preparedStatement.setString(3, student.getSex());
            preparedStatement.setString(4, student.getAddress());

            int row = preparedStatement.executeUpdate();

            if (row > 0) {
                return row;
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            connection.close();
        }

        return 0;
    }

    public int delete(int sid) throws Exception {

        Connection connection = null;

        try {

            connection = dataSource.getConnection();
            String sql = "DELETE FROM student WHERE sid=?";
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1, sid);

            int row = preparedStatement.executeUpdate();

            if (row > 0) {
                return row;
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            connection.close();
        }

        return 0;
    }

    public List<Student> selectAll() throws Exception {
        Connection connection = null;

        try {

            connection = dataSource.getConnection();
            String sql = "select * from student";
            PreparedStatement preparedStatement = connection.prepareStatement(sql);

            ResultSet resultSet = preparedStatement.executeQuery();

            List<Student> students = new ArrayList<Student>();
            while (resultSet.next()) {
                Student student = new Student();
                student.setSid(resultSet.getInt("sid"));
                student.setSname(resultSet.getString("sname"));
                student.setSex(resultSet.getString("sex"));
                student.setAddress(resultSet.getString("address"));
                students.add(student);
            }
            return students;

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            connection.close();
        }

        return null;
    }

    public int update(Student student) throws Exception {
        Connection connection = null;

        try {

            connection = dataSource.getConnection();
            String sql = "UPDATE student SET sname=?,age=?,sex=?,address=? WHERE sid=?";
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, student.getSname());
            preparedStatement.setInt(2, student.getAge());
            preparedStatement.setString(3, student.getSex());
            preparedStatement.setString(4, student.getAddress());
            preparedStatement.setInt(5, student.getSid());

            int row = preparedStatement.executeUpdate();

            if (row > 0) {
                return row;
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            connection.close();
        }

        return 0;
    }
}

SchoolService代碼:

package org.zero01.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.zero01.dao.DAO;
import org.zero01.pojo.Student;

import java.util.List;

@Component("schoolService")
public class SchoolService implements Service {

    @Autowired
    private DAO dao;

    public int enterSchool(Student student) {
        try {
            return dao.insert(student);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    public int dropOut(int sid) {
        try {
            return dao.delete(sid);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    public List<Student> getStudents() {
        try {
            return dao.selectAll();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public int updateData(Student student) {
        try {
            return dao.update(student);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }
}

SchoolAction代碼:

package org.zero01.view;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.zero01.pojo.Student;
import org.zero01.service.Service;

import java.util.List;

@Component("stuAction")
public class SchoolAction implements View {

    @Autowired
    private Service schoolService;

    public int enterSchool(Student student) {
        return schoolService.enterSchool(student);
    }

    public int dropOut(int sid) {
        return schoolService.dropOut(sid);
    }

    public List<Student> getStudents() {
        return schoolService.getStudents();
    }

    public int updateData(Student student) {
        return schoolService.updateData(student);
    }
}

從以上的代碼能夠看到,咱們沒有在哪個類裏寫了關於任何實例化對象的代碼,而是把實例化這項工做交給Spring容器去幫咱們完成,這樣每一個類都不須要去管理、維護本身的依賴對象,只須要完成本身業務代碼便可,這樣弱化了類與類之間的依賴,讓代碼的複雜度下降,每一個類都只須要維護本身的業務代碼便可,這是Spring的IOC模塊給咱們帶來的好處。並且每一個類都依賴的是接口,而不是具體的實現類,符合依賴倒轉原則,不會致使代碼緊耦合,當具體的實現類被替換時,不會影響到其餘類。

測試代碼:

package org.zero01;

import org.json.JSONObject;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.zero01.view.View;
import org.zero01.pojo.Student;

import java.util.HashMap;
import java.util.Map;

public class Test {

    public static void main(String[] args) {

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

        View view = (View) app.getBean("stuAction");
        Student student = (Student) app.getBean("student");

        System.out.println("enterSchool() 影響行數:" + view.enterSchool(student));
        System.out.println("dropOut() 影響行數:" + view.dropOut(25));

        Map<String, Object> map = new HashMap<String, Object>();
        map.put("studentList", view.getStudents());
        map.put("length", view.getStudents().size());
        System.out.println(new JSONObject(map));

        student.setSname("小剛");
        student.setAddress("長沙");
        student.setAge(18);
        student.setSid(29);
        System.out.println("updateData() 影響行數:" + view.updateData(student));
    }
}

運行結果:

enterSchool() 影響行數:1
dropOut() 影響行數:1
{
  "studentList": [
    {
      "address": "南京",
      "sname": "小明",
      "sex": "男",
      "age": 0,
      "sid": 26
    },
    {
      "address": "南京",
      "sname": "小明",
      "sex": "男",
      "age": 0,
      "sid": 27
    },
    {
      "address": "南京",
      "sname": "小明",
      "sex": "男",
      "age": 0,
      "sid": 28
    },
    {
      "address": "南京",
      "sname": "小明",
      "sex": "男",
      "age": 0,
      "sid": 29
    },
    {
      "address": "南京",
      "sname": "小明",
      "sex": "男",
      "age": 0,
      "sid": 30
    },
    {
      "address": "南京",
      "sname": "小明",
      "sex": "男",
      "age": 0,
      "sid": 31
    }
  ],
  "length": 6
}
updateData() 影響行數:1
相關文章
相關標籤/搜索