Spring学习之(四)基于注解的组件扫描

本文是学习过程中的笔记内容,你们看了之后写出的代码都是BUG,不要怪我。哈哈哈~~

1、什么是组件扫描

1)、指定一个包路径,Spring会自动扫描改包及子包所有组件类,当发现组件类定义前有特定的注解标记时,就将该组件纳入到Spring容器。

2)、组件扫描可以替代大量的XML配置<bean>定义

2、指定扫描类路径

使用组件扫描,需要在applicationContext.xml文件配置中指定扫描类路径;

在容器实例化时会自动进行扫描

  • 如下代码示例:
<!-- 开启组件扫描后,会扫描指定包及其子包下的所有类 -->
	<context:component-scan base-package="com.ohiambest"></context:component-scan>

3、自动扫描的注解标记

Spring容器并不是将配置到包中的所有类都进行加载。只有在组件前面有Spring的特定标记时,才会扫描到Spring的容器;

如下是注解标记列表

注解标记

描述

@Component

通用注解

@Name

通用注解

@Respository

持久层注解

@Service

业务层组件注解

@Controller

控制层组件注解

4、自动扫描组件的命名

1)、当一个组件在扫描的过程中被检测到时,会生成一个默认的id值,默认id为小写开头的类名称。

2)、我们也可以通过注解标记,自定义id

默认的id采用类名的首字母小写,示例代码:

package com.ohiambest.service;

import org.springframework.stereotype.Service;

/**
 * 将我们的类声明成一个service组件,spring会自动扫描到容器中<br/>
 * 
 * 并且id的值为类名的小写开头:orderInfoService
 * 
 * @author Administrator
 *
 */
@Service
public class OrderInfoService {

}

如下我们给OrderInfoRepository修改成自定义的id值

package com.ohiambest.dao;

import org.springframework.stereotype.Repository;

/**
 * 
 * @author zhang_wei
 *
 */
// 这里通过标记,修改默认的id名称
@Repository("orderInfoMapper")
public class OrderInfoRepository {

}

5、指定组件的作用域

1)、指定组件的作用域我们可以使用@Scope注解进行自定义

2)、在Spring中,被Spring管理的组件,默认的作用域都是singleton

如下示例,将作用域改为原型模式:

@Scope("prototype") // 修改作用域为原型模式
public class OrderInfoRepository {

}

6、初始化和销毁回调

复习:

1)、我们前面使用xml配置的方式可以指定类的初始化和销毁的回调方法,分别使用的是init-methoddestroy-method

2)、如果是容器级别的全局指定,则分别使用的是default-init-methoddefault-destroy-method

注解的方式指定初始化和销毁回调

3)、这里我们使用注解的方式来指定初始化和销毁的回调,分别使用@PostConstruct注解和@PreDestroy指定初始化和销毁回调方法

6.1、代码

如下代码示例:

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class ExampleMessageBean {

    @PostConstruct
    public void init(){
		System.out.println("ExampleMessageBean...init");
    }
    @PreDestroy
    public void destroy(){
		System.out.println("ExampleMessageBean...destroy");
    }
}

6.2、测试

通过编写测试用例,我们可以发现控制台的输出内容如下:

spring aop 扫描所有controller spring组件扫描_初始化

测试用例的代码如下:

@Test
public void testScan(){
	String config = "config/applicationContext-scan.xml";
	AbstractApplicationContext context = new ClassPathXmlApplicationContext(config);
	context.close();
}

7、指定注入依赖关系

具有依赖关系的Bean对象,利用下面任意一种注解都可以实现关系注入

  • @Resource
  • @Autowired/@Qualifier
  • @Inject/@Named

7.1、 @Resource注解

1)、@Resource 注解标记可以用在字段定义或者setter方法定义前面,默认首先按名称匹配注入,然后按类型匹配注入

2)、但是,当遇到多个匹配的Bean是注入会发生错误,可以显示的指定名称

例如:@Resource(name="oracleUserDao")

示例代码:

@Resource(name="mySqlUserDao")
private UserDao userDao;

7.2、 @Autowired / @Qualifier 注解

1)、@Autowired 注解标记一般用在Bean的属性及setter方法上,默认是按照类型进行注入的

2)、一般数据库Dao层的注解,我们使用@Autowired比较多

3)、由于@Autowired默认是按照类型进行注入的,所以当遇到多个匹配的Bean时,会发生错误

4)、因此,我们需要配合@Qualifier注解进行使用,效果和@Resource(name="oracleUserDao")一样

示例代码:

@Autowired
@Qualifier("mySqlUserDao")
private UserDao userDao;

7.3 、@Inject / @Named 注解

1)、@Inject 注解标记是Spring 3.0开始新增的对JSR-330标准的支持,使用前需要添加JSR-330的jar包,使用的方法同@Autowired相似

2)、@Inject当遇到多个相同类型的Bean时,也会报错,这时需要使用@Named来进行指定

pom.xml中需要引入相关的jar包

<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>

示例代码如下:

//@Inject
private UserDao userDao;

@Inject
public void setUserDao(@Named("mySqlUserDao")UserDao userDao) {
	this.userDao = userDao;
}

8、注入Spring的表达式

1)、使用@Value注解可以注入Spring表达式的值,

2)、使用Spring的表达式,我们需要在XML文件中配置指定要注入的properties文件

3)、Spring的表达式有一个专门的SPEL表达式语言进行支持

我们这里以JDBCDataSource为例进行演示:

db.properties的内容如下:

driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:xe
user=david
password=qwer1234

JDBCDataSource的代码如下配置:

package com.ohiamcool.util;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

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

/**
 * 数据库连接工具类
 * 
 * @author zhang_wei
 *
 */
@Component
public class JDBCDataSource implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private String driver;
	@Value("#{dbProps.url}")
	private String url;
	@Value("#{dbProps.user}")
	private String user;
	@Value("#{dbProps.password}")
	private String password;
	public String getDriver() {
		return driver;
	}
	@Value("#{dbProps.driver}")
	public void setDriver(String driver) {
		try {
			Class.forName(driver);
			this.driver = driver;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	public Connection getConnecttion() throws SQLException{
		Connection connection = DriverManager.getConnection(url, user, password);
		return connection;
	}
	
	public void colse(Connection conn){
		if(conn !=null) {
			try {
				conn.close();
			} catch (Exception e) {
			}
		}
	}
	
	public String getUrl() {
		return url;
	}
	public void setUrl(String url) {
		this.url = url;
	}
	public String getUser() {
		return user;
	}
	public void setUser(String user) {
		this.user = user;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
}

spring的配置文件如下:

<context:component-scan base-package="com.ohiamcool"></context:component-scan>
<!-- 引用配置文件 -->
<util:properties id="dbProps" location="classpath:config/db.properties"/>

8.1、编写测试用例:

这里通过编写测试用例测试我们的自动注入的结果

@Test
	public void testConfig() throws Exception{
		String configLocation = "config/applicationContext-scan.xml";
		AbstractApplicationContext context = new ClassPathXmlApplicationContext(configLocation);
		
		JDBCDataSource dataSource = context.getBean(JDBCDataSource.class);
		System.out.println(dataSource);
		Connection conn = dataSource.getConnecttion();
		System.out.println(conn);
		
		context.close();
		
	}

运营测试用例之后的输出结果为如下图:

spring aop 扫描所有controller spring组件扫描_spring_02