从零到英雄:使用Spring打造强大的企业级应用-中
前言
Spring中bean有三种装配机制,分别是:
- 在xml中显式配置
- 在java中显式配置
- 隐式的bean发现机制和自动装配
自动化的装配bean。
Spring的自动装配需要从两个角度来实现,或者说是两个操作:
- 组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;
- 自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;
组件扫描和自动装配组合发挥巨大威力,使得显示的配置降低到最少。
推荐不使用自动装配xml配置 , 而使用注解
①byName
autowire byName (按名称自动装配)
<bean id="user" class="com.yu.pojo.User" autowire="byName">
<property name="name" value="奇遇少年"/>
</bean>
②byType
<bean id="user" class="com.yu.pojo.User" autowire="byType">
<property name="name" value="奇遇少年"/>
</bean>
注解开发
为了简化配置,Spring支持使用注解代替xml配置。jdk1.5开始支持注解,spring2.5开始全面支持注解。
Spring常用注解
注解开发准备工作
如果要使用注解开发必须要开启组件扫描,这样加了注解的类才会被识别出来。Spring才能去解析其中的注解。
注解装配在 Spring 中是默认关闭的。所以需要在 Spring 文件中配置一下才能使用基于注解的装配 模式。
而自动装配就需要注解扫描,这里有两种开启注解扫描的方式,即
导包: xmlns:context="http://www.springframework.org/schema/context"
开启属性注解支持!
<context:annotation-config/>
和
导包:xmlns:context="http://www.springframework.org/schema/context"
<!--启动组件扫描,指定对应扫描的包路径,该包及其子包下所有的类都会被扫描,加载包含指定注解的类-->
<context:component-scan base-package="com.yu"/>
注意:
<context:annotation-config/>
可以帮助我们识别@Antowired注
解,但是不能帮我我们识别@Component
、@Controller
、@Service等这些注解。
-<context:component-scan>
除了具有<context:annotation-config />
的功能之外,还具有自动将带有@component
、@service
、@Repository
等注解的对象注册到spring容器中的功能。
IOC相关注解
@Component,@Controller,@Service ,@Repository 作用在类上
类 | 注解 |
---|---|
Service类 | @Service |
Dao类 | @Repository |
Controller类 | @Controller |
其他类 | @Component |
例如:
配置
<?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: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 https://www.springframework.org/schema/context/spring-context.xsd">
<!--启动组件扫描,指定对应扫描的包路径,该包及其子包下所有的类都会被扫描,加载包含指定注解的类-->
<context:component-scan base-package="com.yu"></context:component-scan>
</beans>
接口和类
public interface UserDao {
public void showUser();
}
@Repository("userDao")
public class UserDaoImpl implements UserDao{
@Override
public void showUser() {
System.out.println("展示用户数据");
}
}
public interface UserService {
public void showUser();
}
@Service("userService")
public class UserDaoImpl implements UserService{
@Autowired
private UserDao userDao;
public void showUser() {
userDao.showUser();
}
}
测试
public class SpringTest {
public static void main(String[] args) {
//创建容器
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取对象
UserService userService = (UserService) app.getBean("userService");
userService.showUser(); //展示用户数据
}
}
DI相关注解
如果一个bean已经放入Spring容器中了。那么我们可以使用下列注解实现属性注入,让Spring容器帮我们完成属性的赋值。
①@Value
主要用于String,Integer等可以直接赋值的属性注入。不依赖setter方法,支持SpEL表达式。
@Service("userService")
public class UserDaoImpl implements UserService{
@Autowired
private UserDao userDao;
@Value("666")
private int total;
@Value("奇遇少年")
private String name;
@Value("#{22+1}")
private Integer age;
public void showUser() {
System.err.println(total+name+age);
userDao.showUser();
}
}
②@AutoWired
Spring会给加了该注解的属性自动注入数据类型相同的对象。
- @Autowired是按类型自动转配的,不支持id匹配
- 需要导入 spring-aop的包,之前导包已包含
@Service("userService")
public class UserDaoImpl implements UserService{
@Autowired
private UserDao userDao;
......
}
required
属性代表这个属性是否是必须
的,默认值为true
。如果是true
的话Spring容器中如果找不到
相同类型的对象完成属性注入就会出现异常
。
③@Qualifier
如果相同类型
的bean在容器中有多个
时,单独使用@AutoWired就不能满足要求,这时候可以再加上@Qualifier
来指定bean的名字
根据byName从容器中获取bean注入。
@Autowired
@Qualifier("userDao2")
private UserDao userDao;
注意:该直接不能单独使用。单独使用没有作用
④@Resource
- @Resource如有指定的name属性,先按该属性进行byName方式查找装配
- 其次再进行默认的byName方式进行装配
- 如果以上都不成功,则按byType的方式自动装配
- 都不成功,则报异常
//如果允许对象为null,设置required = false,默认为true
@Resource(name = "userDao2")
private UserDao userDao;
结论:先进行byName查找,失败;再进行byType查找,成功。
⑤@scope
- singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。
- prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收
@Controller("user")
@Scope("prototype")
public class User {
@Value("奇遇少年")
public String name;
}
xml配置文件相关注解
①@Configuration
标注在类上,表示当前类是一个配置类。我们可以用注解类来完全替换掉xml配置文件。
注意:如果使用配置类替换了xml配置,spring容器要使用:AnnotationConfigApplicationContext
例如:
@Configuration
public class ApplicationContextConfig {
}
②@ComponentScan
可以用来代替context:component-scan标签来配置组件扫描。
basePackages属性来指定要扫描的包。
注意要加在配置类上。
@Configuration
@ComponentScan(basePackages = "com.yu")//指定要扫描的包
public class ApplicationContextConfig {
}
③@Bean
可以用来代替bean标签,主要用于第三方类的注入。
使用:定义一个方法,在方法中创建对应的对象并且作为返回值返回。然后在方法上加上@Bean注解,注解的value属性来设置bean的名称。
例如:
@Configuration
@ComponentScan(basePackages = "com.yu")
public class ApplicationContextConfig {
@Bean("dataSource")//bean的名称dataSource
public DruidDataSource getDataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
druidDataSource.setUrl("jdbc:mysql://localhost:3306/spring_db");
druidDataSource.setUsername("root");
druidDataSource.setPassword("root");
return druidDataSource;
}
}
注意事项:如果同一种类型的对象在容器中只有一个,我们可以不设置bean的名称。
获取方式如下:
public static void main(String[] args) {
//创建注解容器
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(ApplicationContextConfig .class);
//根据对应类的字节码对象获取
DataSource bean = app.getBean(DataSource.class);
System.out.println(userService);
}
④@PropertySource
可以用来代替context:property-placeholder,让Spring读取指定的properties文件。然后可以使用@Value来获取读取到的值。
使用:在配置类上加@PropertySource注解,注解的value属性来设置properties文件的路径。
然后在配置类中定义成员变量。在成员变量上使用@Value注解来获取读到的值并给对应的成员变量赋值。
例如:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db
jdbc.username=root
jdbc.password=root
读取文件并且获取值
@Configuration
@ComponentScan(basePackages = "com.yu")
@PropertySource("jdbc.properties")
public class ApplicationContextConfig {
@Value("${jdbc.driver}")
private String driverClassName;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DruidDataSource getDataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(driverClassName);
druidDataSource.setUsername(username);
druidDataSource.setUrl(url);
druidDataSource.setPassword(password);
return druidDataSource;
}
}
注意事项:使用@Value获取读到的properties文件中的值时使用的是${key},而不是#{key}。
- 点赞
- 收藏
- 关注作者
评论(0)