在Java项目开发中,使用Spring框架,如果使用传统的XML配置方式,需要首先创建Spring的核心配置文件(applicationContext.xml),然后配置Bean等相关信息。配置文件如下:
调用方式,使用ClassPathXmlApplicationContext类初始化Spring容器对象,然后使用getBean()方法,获取Bean对象。代码如下:
public static void main(String[] args)
{
//初始化Spring容器(上下文对象)
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
//获取Bean对象
UserService userService = (UserService) applicationContext.getBean("userService");
//执行业务逻辑方法,获取用户信息
UserInfo userInfo = userService.getUserInfo();
//打印结果
System.out.println("用户编号:" + userInfo.getUserId());
System.out.println("用户姓名:" + userInfo.getUserName());
System.out.println("博客地址:" + userInfo.getBlogUrl());
System.out.println("备注信息:" + userInfo.getRemark());
}
下面将介绍另外一种Spring配置方式:Java配置方式。
Java配置是 Spring 4.x 推荐的配置方式,可以完全替代XML配置;Java配置也是 Spring Boot 推荐的配置方式。
Java配置相关注解:
注解 | 说明 |
---|---|
@Configuration | 声明当前类是一个配置类,相当于一个Spring配置的XML文件。 |
@Bean | 该注解在方法上使用,声明当前方法的返回值为一个Bean。 |
@ComponentScan | 自动扫描包名下所有使用@Component、@Repository、@Service、@Controller注解的类,并注册为Bean。 |
@WishlyConfiguration | 该注解为@Configuration与@ComponentScan的组合注解,可以替代这两个注解。 |
在项目的开发中会使用Java配置和注解混合配置。何时使用Java配置或者注解配置呢?主要的原则是:全局配置使用Java配置(如:数据库相关配置、MVC相关配置),业务Bean的配置使用注解配置(如:@Component、@Repository、@Service、@Controller)。
【实例】创建Java项目,在项目中使用@Repository、@Service注解。然后使用@ComponentScan注解自动扫描组件。实现获取用户信息业务,并在测试方法中显示用户信息。
(1)创建项目
创建Java项目,搭建项目结构,如下图:
使用Maven进行项目的构建,pom.xml文件的配置如下:
UTF-8
5.2.3.RELEASE
org.springframework
spring-core
${spring.version}
org.springframework
spring-context
${spring.version}
(2)实体层(Entity层)
在Entity目录(实体层),创建用户信息实体类(UserInfo.java)。
package com.pjb.entity;
/**
* 用户信息实体类
* @author pan_junbiao
**/
public class UserInfo
{
private int userId; //用户ID
private String userName; //用户姓名
private String blogUrl; //博客地址
private String remark; //备注
//省略getter与setter方法...
}
(3)数据访问层(Dao层)
创建用户信息数据库访问接口(UserDao.java)。
package com.pjb.dao;
import com.pjb.entity.UserInfo;
/**
* 用户信息数据库访问接口
* @author pan_junbiao
**/
public interface UserDao
{
/**
* 获取用户信息
*/
public UserInfo getUserInfo();
}
创建用户信息数据库访问类(UserDaoImpl.java),并标识@Repository注解,实现UserDao接口,实现获取用户信息,模拟读取数据库获取数据方法。
package com.pjb.dao.impl;
import com.pjb.dao.UserDao;
import com.pjb.entity.UserInfo;
import org.springframework.stereotype.Repository;
/**
* 用户信息数据库访问类
* @author pan_junbiao
**/
@Repository
public class UserDaoImpl implements UserDao
{
/**
* 获取用户信息
*/
public UserInfo getUserInfo()
{
//获取用户信息(模拟读取数据库获取数据)
UserInfo userInfo = new UserInfo();
userInfo.setUserId(1);
userInfo.setUserName("pan_junbiao的博客");
userInfo.setBlogUrl("https://blog.csdn.net/pan_junbiao");
userInfo.setRemark("您好,欢迎访问 pan_junbiao的博客");
return userInfo;
}
}
(4)业务逻辑服务层(Service层)
创建用户信息业务逻辑接口(UserService.java)。
package com.pjb.service;
import com.pjb.entity.UserInfo;
/**
* 用户信息业务逻辑接口
* @author pan_junbiao
**/
public interface UserService
{
/**
* 获取用户信息
*/
public UserInfo getUserInfo();
}
用户信息业务逻辑类(UserServiceImpl.java),并实现UserService接口。
package com.pjb.service.impl;
import com.pjb.dao.UserDao;
import com.pjb.entity.UserInfo;
import com.pjb.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* 用户信息业务逻辑类
* @author pan_junbiao
**/
@Service
public class UserServiceImpl implements UserService
{
@Autowired
private UserDao userDao;
/**
* 获取用户信息
*/
public UserInfo getUserInfo()
{
return userDao.getUserInfo();
}
}
(5)Java配置类(Config层)
创建Java配置类(JavaConfig.java)。
package com.pjb.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* Java配置类
* @author pan_junbiao
**/
@Configuration
@ComponentScan({"com.pjb.dao","com.pjb.service"})
public class JavaConfig
{
}
代码说明:
在该类中使用@Configuration注解声明当前类是一个配置类;
使用@ComponentScan注解自动扫描包名下所有使用@Component、@Repository、@Service、@Controller注解的类,并注册为Bean。
@ComponentScan注解扫描多个包文件:
//方式一:
@ComponentScan({"com.pjb.dao","com.pjb.service"})
//方式二:
@ComponentScan("com.pjb.*")
(6)测试(Test层)
创建测试类(MyTest.java)。
import com.pjb.config.JavaConfig;
import com.pjb.entity.UserInfo;
import com.pjb.service.UserService;
import com.pjb.service.impl.UserServiceImpl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* 测试类
* @author pan_junbiao
**/
public class MyTest
{
public static void main(String[] args)
{
//使用AnnotationConfigApplicationContext作为Spring容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
//获取声明配置的UserService的Bean
UserService userService = context.getBean(UserServiceImpl.class);
//执行业务逻辑方法,获取用户信息
UserInfo userInfo = userService.getUserInfo();
//打印结果
System.out.println("用户编号:" + userInfo.getUserId());
System.out.println("用户姓名:" + userInfo.getUserName());
System.out.println("博客地址:" + userInfo.getBlogUrl());
System.out.println("备注信息:" + userInfo.getRemark());
}
}
代码说明:
使用AnnotationConfigApplicationContext可以实现基于Java的配置类(包括各种注解)加载Spring的应用上下文。避免使用application.xml进行配置。相比XML配置,更加便捷。
执行结果:
【实例】修改上述实例,使用@Configuration注解和@Bean注解。
(1)数据访问层(Dao层)
修改用户信息数据库访问类(UserDaoImpl.java),注释掉@Repository注解,表示没有使用@Repository注解声明Bean。
package com.pjb.dao.impl;
import com.pjb.dao.UserDao;
import com.pjb.entity.UserInfo;
/**
* 用户信息数据库访问类
* @author pan_junbiao
**/
//表示没有使用@Repository注解声明Bean
//@Repository
public class UserDaoImpl implements UserDao
{
/**
* 获取用户信息
*/
public UserInfo getUserInfo()
{
//获取用户信息(模拟读取数据库获取数据)
UserInfo userInfo = new UserInfo();
userInfo.setUserId(1);
userInfo.setUserName("pan_junbiao的博客");
userInfo.setBlogUrl("https://blog.csdn.net/pan_junbiao");
userInfo.setRemark("您好,欢迎访问 pan_junbiao的博客");
return userInfo;
}
}
(2)业务逻辑服务层(Service层)
修改用户信息业务逻辑类(UserServiceImpl.java)。
1、注释掉@Service注解,表示没有使用@Service注解声明Bean。
2、注释掉@Autowired注解,表示没有使用@Autowired注解注入Bean。
3、添加UserDao对象的set方法(注意:一定要添加)。
package com.pjb.service.impl;
import com.pjb.dao.UserDao;
import com.pjb.entity.UserInfo;
import com.pjb.service.UserService;
/**
* 用户信息业务逻辑类
* @author pan_junbiao
**/
//表示没有使用@Service注解声明Bean
//@Service
public class UserServiceImpl implements UserService
{
//表示没有使用@Autowired注解注入Bean
//@Autowired
private UserDao userDao;
public void setUserDao(UserDao userDao)
{
this.userDao = userDao;
}
/**
* 获取用户信息
*/
public UserInfo getUserInfo()
{
return userDao.getUserInfo();
}
}
(3)Java配置类(Config层)
修改Java配置类(JavaConfig.java)。
package com.pjb.config;
import com.pjb.dao.UserDao;
import com.pjb.dao.impl.UserDaoImpl;
import com.pjb.service.UserService;
import com.pjb.service.impl.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Java配置类
* @author pan_junbiao
**/
@Configuration
public class JavaConfig
{
/**
* 创建UserDao的Bean对象
* 用于注入到UserService的Bean对象中
*/
@Bean
public UserDao userDao()
{
UserDaoImpl userDaoImpl = new UserDaoImpl();
return userDaoImpl;
}
/**
* 创建UserService的Bean对象
* 方式一:
* 使用@Bean注解的autowire属性,
* Autowire.BY_TYPE表示通过类型进行自动装配
*/
@Bean(autowire = Autowire.BY_TYPE)
public UserService userService()
{
UserServiceImpl userServiceImpl = new UserServiceImpl();
return userServiceImpl;
}
/**
* 创建UserService的Bean对象
* 方式二:
* 注入UserDao的bean时候直接调用userDao()方法。
*/
/*@Bean
public UserService userService()
{
UserServiceImpl userServiceImpl = new UserServiceImpl();
userServiceImpl.setUserDao(userDao());
return userServiceImpl;
}*/
/**
* 创建UserService的Bean对象
* 方式三:
* 直接将UserDao作为参数给userService()方法,
* 在Spring容器中,只要容器中存在某个Bean,
* 就可以在另外一个Bean的声明方法的参数中注入。
*/
/*@Bean
public UserService userService(UserDao userDao)
{
UserServiceImpl userServiceImpl = new UserServiceImpl();
userServiceImpl.setUserDao(userDao);
return userServiceImpl;
}*/
}
执行结果:
方式一:
/**
* 创建UserService的Bean对象
* 方式一:
* 使用@Bean注解的autowire属性,
* Autowire.BY_TYPE表示通过类型进行自动装配
*/
@Bean(autowire = Autowire.BY_TYPE)
public UserService userService()
{
UserServiceImpl userServiceImpl = new UserServiceImpl();
return userServiceImpl;
}
@Bean注解提供的属性如下:
value:name属性的别名,在不需要其他属性时使用,也就是说value 就是默认值。
name:此bean 的名称,或多个名称,主要的bean的名称加别名。如果未指定,则bean的名称是带注解方法的名称。如果指定了,方法的名称就会忽略,如果没有其他属性声明的话,bean的名称和别名可能通过value属性配置。
autowire :此注解的方法表示自动装配的类型,返回一个Autowire类型的枚举,我们来看一下Autowire枚举类型的概念。
// 枚举确定自动装配状态:即,bean是否应该使用setter注入由Spring容器自动注入其依赖项。
// 这是Spring DI的核心概念
public enum Autowire {
// 常量,表示根本没有自动装配。
NO(AutowireCapableBeanFactory.AUTOWIRE_NO),
// 常量,通过名称进行自动装配
BY_NAME(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME),
// 常量,通过类型进行自动装配
BY_TYPE(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE);
private final int value;
Autowire(int value) {
this.value = value;
}
public int value() {
return this.value;
}
public boolean isAutowire() {
return (this == BY_NAME || this == BY_TYPE);
}
}
autowire的默认值为No,默认表示不通过自动装配。
方式二:
/**
* 创建UserService的Bean对象
* 方式二:
* 注入UserDao的bean时候直接调用userDao()方法。
*/
@Bean
public UserService userService()
{
UserServiceImpl userServiceImpl = new UserServiceImpl();
userServiceImpl.setUserDao(userDao());
return userServiceImpl;
}
在注入UserDao的bean时候直接调用userDao()方法。
方式三:
/**
* 创建UserService的Bean对象
* 方式三:
* 直接将UserDao作为参数给userService()方法,
* 在Spring容器中,只要容器中存在某个Bean,
* 就可以在另外一个Bean的声明方法的参数中注入。
*/
@Bean
public UserService userService(UserDao userDao)
{
UserServiceImpl userServiceImpl = new UserServiceImpl();
userServiceImpl.setUserDao(userDao);
return userServiceImpl;
}
直接将UserDao作为参数给userService()方法,这也是Spring容器提供的极好功能。在Spring容器中,只要容器中存在某个Bean,就可以在另外一个Bean的声明方法的参数中注入。