Spring注解开发
Spring有两种配置方式:xml配置、注解配置。
注解配置的目的,是为了简化XML配置。
Spring的注解有2种:原始注解、新注解。
1.原始注解
针对于自定义的类,能够进入到类实现代码中去添加“注解”,以注解代替xml配置文件中的标签配置。
注解 | 说明 |
---|---|
@Component | 使用在java类上,用于实例化Bean |
@Controller | 使用在web层类上,用于实例化Bean |
@Service | 使用在service层类上,用于实例化Bean |
@Repository | 使用在dao层类上,用于实例化Bean |
@Autowired | 使用在java类的属性字段上,用于根据类型注入依赖 |
@Qualifier | 结合@Autowired一起使用,用于根据名称进行依赖注入 |
@Resource | 相当于@Autowired+@Qualifier,按照名称进行依赖注入 |
@Value | 为普通属性注入值 |
@Scope | 标注Bean的作用范围 |
@PostConstruct | 使用在方法上,标注该方法是Bean的初始化方法 |
@PreDestroy | 使用在方法上,标注该方法是Bean的销毁方法 |
对比着Spring中XML配置开发来理解。
1.1 XML配置内容
<!--配置Dao层的Bean对象-->
<bean id="userDaoImpl" class="cn.leap.dao.impl.UserDaoImpl">
<property name="username" value="John"/>
</bean>
<!--配置Service层的Bean对象-->
<bean id="userServiceImpl" class="cn.leap.service.impl.UserServiceImpl">
<property name="userDao" ref="userDaoImpl"/>
</bean>
现在要通过”注解“来替换上面的两个标签。
1.2 dao层注解配置
//@Component("userDaoImpl")
@Repository("userDaoImpl") //@Repository 用于dao层实例化Bean
public class UserDaoImpl implements UserDao {
@Value("John")
private String username;
@Value("${jdbc.driver}")//使用SpEL表达式获取外部配置文件的数据
private String driver;
@Override
public void save() {
System.out.println("UserDaoImpl: save()............");
System.out.println(username);
System.out.println(driver);
}
}
外部配置文件 jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db1
jdbc.username=root
jdbc.password=root
1.3 service层的注解配置
//@Component("userService")
@Service("userServiceImpl") //@Service 用于service层实例化Bean
public class UserServiceImpl implements UserService {
/*@Autowired
@Qualifier("userDaoImpl")*/
@Resource(name="userDaoImpl")
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void save() {
userDao.save();
}
}
1.4 XML中配置”组件扫描“功能
在Spring主配置文件applicationContext.xml中进行配置。
这是指定哪个包及其子包下的Bean,告诉Spring,它们需要进行扫描以便识别使用注解配置的类、字段和方法等信息。
<context:component-scan base-package="cn.leap"/>
如果不给Spring配置这个”组件扫描“功能,那么运行测试代码时,会报如下错误
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'userServiceImpl' available
显示没有定义相应的Bean类。其实不是没有定义,而是Spring没找到。
为什么没找到?
原因:”注解“在Java类进行了配置,但还未告诉Spring。
这里的context,是一个命名空间,需要在Spring配置文件中,对它进行配置。
context命名空间的配置
Spring配置文件根标签标签中,初始内容如下
<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.xsd">
</beans>
配置context命名空间后,如下:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
1.5 测试代码
public class SpringAnnotationTest {
/**
* 原始注解测试
*/
@Test
public void testSpringOriginAnnotation() {
String config = "applicationContext.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(config);
UserService service = (UserService) context.getBean("userServiceImpl");
service.save();
}
}
1.6 运行结果
没有配置组件扫描时,报错:
org.springframework.bean.factory.NoSuchBeanDefinitionException: No bean named ‘userServiceImpl’ available
[外链图片转存失败(img-kVuExVOs-1569086800475)(C:\Users\ASUS\AppData\Local\Temp\1562435360199.png)]
配置组件扫描后,运行正常。
userDaoImpl: save()............
John
com.mysql.jdbc.Driver
1.7 分析总结
注解配置是简化了XML配置,但会发现,并没有完全取代XML配置,如**”组件扫描“**标签就仍然是在XML文件中进行配置的。而且,原始注解也取代不了此标签。
对于那些无法用XML进行配置的内容,Spring团队后来提供了一套”Spring新注解“规则,来实现***Spring的全注解开发***。
但实际应用中,通常都是”XML配置+注解配置“的方式。
2. 新注解
针对原始注解没办法进行注解的xml标签
使用了新注解后,Spring就可以实现”全注解开发“,即XML配置文件可以不再需要了。
注解 | 说明 |
---|---|
@Configuration | 用于类上,指定当前类是一个 Spring 配置类,当创建容器时会从该类上加载注解 |
@ComponentScan | 用于指定 Spring 在初始化容器时要扫描的包。 作用和在 Spring 的 xml 配置文件中的 <context:component-scan base-package=“com.yeats”/>一样 |
@Bean | 使用在方法上,标注将该方法的返回值存储到 Spring 容器中 |
@PropertySource | 用于加载.properties 文件中的配置 |
@Import | 用于导入其他配置类 |
(1)非自定义类的标签
外部的依赖包,源码进去了,也修改不了,所有没法在上面添加“注解”。
(当然也不是完全不行,如果修改源码后,重新导入就可以了,但那实在太麻烦了,一般没人那样做)
如:C3P0数据库连接池的实现类 ComboPooledDataSource,它下面这段XML配置,就无法用Spring原始注 解进行配置。
<bean id="dataSource1" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
(2)标签
<import sources="spring-config-dataSource"/>
(3)加载properties配置文件的标签
<context:property-placeholder location="classpath:jdbc.properties"/>
(4)组件扫描标签
<context:component-scan base-package="cn.leap"/>
2.1 创建Spring核心配置类 @Configuration
通常都命名为 SpringConfiguration.java 它相当于取代了applicationContext.xml
创建类文件后,需要通过注解声明它是Spring核心配置类。
@Configuration//声明该类为Spring核心配置类
public class SpringConfiguration {
}
2.2 @ComponentScan: 取代”组件扫描“标签
<context:component-scan base-package=“cn.leap”/>
@Configuration//声明该类为Spring核心配置类
@ComponentScan("cn.leap")//取代组件扫描标签
public class SpringConfiguration {
}
2.3 @PropertySource: 取代加载properties配置文件的标签
<context:property-placeholder location="classpath:jdbc.properties"/>
外部配置文件 jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db1
jdbc.username=root
jdbc.password=root
Spring中的配置文件,通常会根据不同的功能类别,单独建配置文件。
这里,可以新建一个数据源配置类:DataSourceConfiguration.java
@PropertySource("classpath:jdbc.properties")//加载配置文件
public class DataSourceConfiguration {
/**
* SpEL表达式获取键值
*/
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
}
注意:
这只是加载了配置文件,还并没有用它。一个完整的DataSourceConfiguration配置类,应该对外提供一个方法,用于传递DataSource对象
2.4 @Import: 取代标签
<import sources="spring-config-dataSource"/>
主配置类中,导入其他配置类。
@Configuration//声明该类为Spring核心配置类
@ComponentScan("cn.leap")//指定进行组件扫描的包
@Import({DataSourceConfiguration.class})//导入其他配置类
public class SpringConfiguration {
}
2.5 @Bean: 取代非定义类的标签
@Bean 使用在方法上,标注将该方法的返回值存储到Spring容器中
非定义类,原先在XML中的配置如下:
<bean id="dataSource1" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
使用在**“方法”**上,那该方法写什么?在哪儿写?
它属于哪块功能,就写到对应的配置类中去。
这个ComboPooledDatasource类是跟数据源相关的,所以把它写到DataSourceConfiguration.java中去
@PropertySource("classpath:jdbc.properties")//加载配置文件
public class DataSourceConfiguration {
/**
* SpEL表达式获取键值
*/
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean(name = "dataSource")//指示Spring将当前方法的返回值以指定名称放到Spring容器中
public DataSource getDataSource() throws Exception {
//获取连接池对象
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
//返回DataSource对象
return ds;
}
}
2.6 测试代码
测试什么?加载核心配置类创建Spring容器
public class SpringAnnotationTest {
/**
* Spring新注解的测试
*/
@Test
public void testSpringNewAnnotation() throws Exception {
//创建 Spring容器,并从容器中获取数据源
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);//必须指明主配置类的字节码文件
DataSource dataSource = (DataSource) context.getBean("dataSource");
//从数据源中获取连接
Connection connection = dataSource.getConnection();
System.out.println(connection);
//dao、service的测试
UserService userService = (UserService) context.getBean("userServiceImpl");
userService.save();
}
/**
* Spring原始注解测试
*/
@Test
public void testSpringOriginAnnotation() {
String config = "applicationContext.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(config);
UserService service = (UserService) context.getBean("userServiceImpl");
service.save();
}
}
2.7 分析总结
使用新注解后,再配合上原始注解,就实现了Spring的全注解开发,不用写XML配置。
需要注意两点:
1. 实际开发中,其实是XML配置+注解配置,两者并用,相辅相成的。
2. 所谓的”原始注解“,是指Spring稍早时候提供的注解。使用新注解,也一定会配合原始注解,两者一块使用,才能完成所谓的”Spring全注解开发“。
plicationContext.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(config);
UserService service = (UserService) context.getBean(“userServiceImpl”);
service.save();
}
}
### 2.7 分析总结
使用**新注解**后,再配合上**原始注解**,就实现了Spring的**全注解开发**,不用写XML配置。
需要注意两点:
1. 实际开发中,其实是XML配置+注解配置,两者并用,相辅相成的。
2. 所谓的”原始注解“,是指Spring稍早时候提供的注解。使用新注解,也一定会配合原始注解,两者一块使用,才能完成所谓的”Spring全注解开发“。