基于注解的Spring应用
Spring的注解开发-注解版本和@Component简介
Spring除了xml配置文件进行配置之外,还可以使用注解方式进行配置,注解方式慢慢成为xml配置的替代方案。
Spring提供的注解有三个版本:
- 2.0时代,Spring开始出现注解
- 2.5时代,Spring的Bean配置可以使用注解完成
- 3.0时代,Spring其他配置也可以使用注解完成,进入全注解时代
基于Bean注解,主要是使用注解的方式替代原有xml的bean标签及其标签属性的配置
<bean id="" name="" class="" scope="" lazy-init="" init-method="" destroy-method="" abstract="" autowire="" facatory-bean="" factory-method=""></bean>
使用@Component注解替代标签
xml配置 | 注解 | 描述 |
---|---|---|
bean id=“” class=“” | @Component | 被该注解标识的类,会在指定扫描范围内被Spring加载并实例化 |
Spring的注解开发-@Component使用
//<bean id="userDao" name="com.lucifa.dao.impl.UserDaoImpl"></bean>
@Component("userDao")
public class UserDaoImpl implements UserDao {
}
applicationContext.xml中
使用注解对需要被Spring实例化的Bean进行标注,需要告诉Spring去哪找这些Bean,要配置组件扫描路径
<beans xmlns="..." ...>
<!--注解组件扫描:扫描指定的基本包及其子包下的类,识别使用@Conponent注解>
<context:component-scan base-package="com.luxifa"/>
</beans>
主程序:
public class ApplicationContextTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Object userDao = applicationContext.getBean("userDao");
System.out.println(userDao);
}
}
控制台打印:
com.luxifa.dao.impl.UserDaoImpl@799d4f69
可以通过@Component注解的value属性指定当前Bean实例的beanName,也可以省略不写,不写的情况下为当前类名首字母小写
//获取方式:applicationContext.getBean("userDao");
@Component("userDao")
public class UserDaoImpl implements UserDao {
}
//获取方式:applicationContext.getBean("userDaoImpl");
@Component
public class UserDaoImpl implements UserDao {
}
Spring的注解开发-作用范围等注解使用
Spring通过注解方式去配置之前标签中的那些属性,例如:@Scope
<bean id="" name="" class="" scope="" lazy-init="" init-method="" destroy-method="" abstract="" autowire="" facatory-bean="" factory-method=""></bean>
xml配置 | 注解 | 描述 |
---|---|---|
bean scope=“” | @Scope | 在类上或使用了@Bean标注的方法上,标注Bean的作用范围,取值为singleton或prototype |
bean lazy-init=“” | @Lazy | 在类上或使用了@Bean标注的方法上,标注Bean是否延迟加载,取值为true和false |
bean init-method=“” | @PostConstruct | 在方法上使用,标注Bean的实例化后执行的方法 |
bean destroy-method=“” | @PreDestroy | 在方法上使用,标注Bean的销毁前执行方法 |
@Component("userDao")
@Scope("singleton")
@Lazy(false)
public class UserDaoImple implements UserDao {
public UserDaoImpl() {
System.out.println("userDao创建");
}
@PostConstruct
public void init() {
Syste.out.println("userDao的初始化方法");
}
@PreDestroy
public void destroy() {
System.out.println("userDao的销毁方法");
}
}
Spring的注解开发-@component的三个衍生注解
由于JavaEE开发是分层的,为了每层Bean标识的注解语义化更加明确,@Component又衍生出如下三个注解:
@Component衍生注解 | 描述 |
---|---|
@Repository | 在Dao层类上使用 |
@Service | 在Service层类上使用 |
@Controller | 在web层类上使用 |
@Repository("userDao")
public class UserDaoImpl implements UserDao {}
@Service("userService")
public class UserServiceImpl implements UserService {}
@Controller("userService")
public class UserController {}
Spring的注解开发-依赖注入相关注解
Bean依赖注入的注解,主要是使用注解的方式替代xml的标签完成属性的注入操作
<bean id="" class="">
<property name="" value=""/>
<property name="" ref=""/>
</bean>
Spring主要提供如下注解,用于在Bean内部进行属性注入的:
属性注入注解 | 描述 |
---|---|
@Value | 使用在字段或方法上,用于注入普通数据 |
@Autowired | 使用在字段或方法上,用于根据类型(byType)注入引用数据 |
@Qualifier | 使用在字段或方法上,结合@Autowired,根据名称注入 |
@Resource | 使用在字段或方法上,根据类型名称进行注入 |
@Value
1.
@Scope("singleton")
@Lazy(false)
public class UserDaoImple implements UserDao {
/方式1 @Value("luxifa")
private String username;
//方式2
@Value("luxifa")
public void setUsername(String username) {
this.username = username;
}
@Override
public void show() {
System.out.println(username);
}
}
applicationContext.xml中
<beans xmlns="..." ...>
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--注解组件扫描:扫描指定的基本包及其子包下的类,识别使用@Conponent注解>
<context:component-scan base-package="com.luxifa"/>
</beans>
jdbc.propertie中
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=...
jdbc.url=...
jdbc.password=root...
@Scope("singleton")
@Lazy(false)
public class UserDaoImple implements UserDao {
@Value("${jdbc.driver}")
private String username;
@Override
public void show() {
System.out.println(username);
}
}
@Autowired
如果组件只有一个有参构造器,这个有参构造器的 @Autowired 可以省略,参数位置的组件还是可以自动从容器中获取
@Bean+方法参数:参数从容器中获取,默认不写 @Autowired 效果是一样的,都能自动从容器中获取
//@Component("userService")
@Service("userService")
public class UserServiceImpl implements UserService {
//方式1
@Autowired //根据类型进行注入
private UserDao userDao;
//方式2
//@Autowired 这个地方注解不能省略
public void setSuserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void show() {
System.out.println(userDao);
}
}
@Qualifier
UserDaoImpl.java
@Repository("userDao")
public class UserDaoImpl implements UserDao{
@Override
public void show() {
}
}
UserDaoImpl2.java
@Repository("userDao2")
public class UserDaoImpl2 implements UserDao{
@Override
public void show() {
}
}
//@Component("userService")
@Service("userService")
public class UserServiceImpl implements UserService {
@Autowired //根据类型进行注入,如果同一类型的Bean有多个,尝试根据名字进行儿媳匹配,匹配不成则报错
@Qualifier("userDao2") //在此,结合@Autowired一起使用,作用是根据名称注入相应的Bean
private UserDao userDao;
@Override
public void show() {
System.out.println(userDao);
}
}
@Resource
@Resource单独使用时,相当于@Autowired注解
@Resource(name=“”),相当于 @Autowired+@Qualifier
//@Component("userService")
@Service("userService")
public class UserServiceImpl implements UserService {
//@Autowired //根据类型进行注入,如果同一类型的Bean有多个,尝试根据名字进行儿媳匹配,匹配不成则报错
//@Qualifier("userDao2") //在此,结合@Autowired一起使用,作用是根据名称注入相应的Bean
@Resource(name="userDao2") //不指定名称参数时,根据类型注入,指定名称就根据名称注入
private UserDao userDao;
@Override
public void show() {
System.out.println(userDao);
}
}
Spring的注解开发-非自定义Bean的配置
非自定义Bean不能像自定义Bean一样使用@Component进行管理,非自定义Bean要通过工厂的方式进行实例化,使用@Bean标注方法即可,@Bean的属性为beanName,如不指定为当前工厂方法名称
@Component
public class OtherBean {
//将方法返回值bean实例以@Bean注解指定的名称存储到Spring容器中
@Bean("dataSource")
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/mytatis");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
}
此外,工厂方法所在类必须要被Spring管理。
如果@Bean工厂方法需要参数的话,则有如下几种注入方式:
- 使用@Autowired根据类型自动进行Bean的匹配,@Autowired可以省略;
- 使用@Qualifier根据名称进行Bean的匹配
- 使用@Value根据名称进行普通数据类型匹配
@Bean
@Autowired //根据类型匹配参数
public Object objectDemo01(UserDao userDao) {
System.out.println(userDao);
return new Object();
}
@Bean
public Object objectDemo02(@Qualifier("userDao2") UserDao userDao,@Value("${jdbc.username}") String username) {
System.out.println(userDao);
System.out.println(username);
return new Object();
}
@Repository("userDao2")
public class UserDaoImpl2 implements UserDao {
@Override
public void show () {
}
}
Spring的注解开发-Spring配置类的开发
@Component等注解替代了bean标签,但是像import、context:componentScan等非bean标签该如何使用注解替代?
<!--加载properties文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--组件扫描-->
<context:component-scan base-package="com.luxifa"/>
<!--引入其他xml文件-->
<import resource="classpath:beans.xml"/>
定义一个配置类替代原有的xml配置文件,标签以外的标签,一般都是在配置上使用注解完成的
@Configuration注解标识的类为配置类,替代原有xml配置文件,该注解第一个作用是标识该类是一个配置类,四二个作用是具备@Component作用
@Configuration
public class ApplicationConTextConfig {}
@ComponentScan组件扫描配置,替代原有xml中的<context:component-scan base-package=“”/>
@Configuration
@ComponentScan({"com.luxifa.service","com.luxifa.dao"})
public class ApplicationContextConfig {}
base-package的配置方式:
- 指定一个或多个包名:扫描指定包及其子包下使用注解的类
- 不配置包名:扫描当前@ComponentScan注解配置类所在包及其子包下的类
@PropertySource注解用于记载外部properties资源配置,替代原有xml中的<context:property-placeholder location=“”/>配置
@Configuration
@ComponentScam
@PropertySource({"classpath:jdbc.properties","classpath:xxx.properties"})
public class ApplicationContextCOnfig {}
@Import用于加载其他配置类,替代原有xml中的import resource=“classpath:beans.xml” 配置
@Configuration
@ComponentScan
@PropertySource("classpath:jdbc.properties")
@Import(OtherConfig.class)
public class ApplicationContextCOnfig {}
public class OtherBean {
//将方法返回值bean实例以@Bean注解指定的名称存储到Spring容器中
@Bean("dataSource")
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/mytatis");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
}
Spring的注解开发-Spring配置其他注解
扩展:@Primary注解用于标注相同类型的Bean优先被使用权,@Primary是Spring3.0引入的,与@Component和@Bean一起使用,标注该Bean的优先级更高,则在通过类型获取Bean或通过@Autowired根据类型进行注入时,会选用优先级更高的
@Service("userService")
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public void show() {
System.out.println(userDao);
}
}
@Repository("userDao")
public class UserDaoImpl implements UserDao {
@Override
public void show() {
}
}
@Repository("userDao2")
@Primary
public class UserDaoImpl2 implments UserDao {
@Override
public void show() {
}
}
主程序:
public class ApplicationContextTest {
public static void main(String[] args) {
//注解方式去加载Spring的核心配置类
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = applicationContext.getBean(UserService.class);
userService.show();
}
}
控制台输出:
com.luxifa.dao.impl.UserDaoImpl2@5fb230b4
@Primary也这样使用
@Bean
public UserDao userDao01() {return new UserDaoImpl();}
@Bean
@Primary
public UserDao userDao02() {return new UserDaoImpl2();}
扩展:@Profile注解的作用同于xml中的profile属性,用于进行环境切换使用
<beans profile="test">
注解@Profile标注在类或方法上,标注当前产生的Bean从属于哪个环境,只有激活了当前环境,被标注的Bean才能被注册到Spring容器里。不指定环境的Bean,任何环境下都能注册到Spring容器里
@Repository("userDao")
@Profile("test")
public class UserDaoImpl implements UserDao {
}
主程序:
public class ApplicationContextTest {
public static void main(String[] args) {
System.setProperty("spring.profiles.active","test");
//注解方式去加载Spring的核心配置类
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
Object userDao= applicationContext.getBean("userDao");
System.out.println(userDao);
}
}
控制台打印:
com.luxifa.dao.impl.UserDaoImpl@33afa13b