详细的描述了Spring中的注解开发。
注解开发定义Bean
步骤:
1.使用@Component定义Bean
以下两种方式都可以定义Bean
@Component(“Bean的名称”)
@Component
其中第一种方式可以使用 ctx.getBean(“名称”)
其中第二种方式只能使用 ctx.getBean(“类型.class”) 因为没有指定名称
2.核心配置文件中通过组件扫描加载Bean
<context:component-scan base-package="wang"/> <!-- 递归扫描 wang -->注意:
Spring提供@Component注解的三个衍生注解
@controller:用于表现层bean定义
@service:用于业务层bean定义.
@Repository:用于数据层bean定义
样例代码:
impl实现类:
package wang.dao.impl;
import org.springframework.stereotype.Component;import wang.dao.Dao;
@Component("dao")public class DaoImpl implements Dao { @Override public void save() { System.out.println("Dao save() ..."); }}xml配置文件:
<?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 http://www.springframework.org/schema/context/spring-context.xsd ">
<context:component-scan base-package="wang"/>
</beans>主函数:
package wang;
import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import wang.dao.Dao;
public class App4 { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml.bak"); Dao dao = (Dao) ctx.getBean("dao"); dao.save(); }}运行结果:
DaoImpl 上的 @Component 注解显式提供 dao 这个 Bean 名称,XML 中对 wang 包的组件扫描负责发现这个类并注册它。主函数从容器按 dao 取出对象后调用 save(),展示的是注解定义对象、XML 保留扫描入口的组合方式。需要特别核对资源名:示例主函数读取 applicationContext.xml.bak,实际保存的配置文件必须与这个名称一致,否则还没有进入业务方法就会在加载配置阶段失败。
纯注解开发模式
Spring3.0升级了纯注解开发模式,使用Java类替代配置文件,开启了Spring快速开发赛道
如何取消配置文件呢,使用一个配置类来代替配置文件
package wang.config;
import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;
@Configuration@ComponentScan("wang")public class SpringConfig {
}注意:
@ComponentScan(“wang”) 代替了中间的组件扫描器的功能
@Configuration代替了 xml 配置文件中的其他配置,如下图:
原理示意:@Configuration 把 SpringConfig 声明为配置类,@ComponentScan 指定扫描 wang 包,表达原来 XML 的包扫描入口;两种路径都能发现标注组件的 DaoImpl。切换为纯注解时,容器入口也应改为读取配置类。这里对应的是本例的组件扫描配置,不代表加一个注解就能自动搬走全部 XML 功能,其他配置仍需逐项转换。
注意:ComponentScan({“wang.xxx01”, “wang.xxx02”}) 可以扫描多个类
主函数中需要改变一行代码:
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");改为:
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);此时删除xml配置文件运行结果相同:
主函数改用 AnnotationConfigApplicationContext(SpringConfig.class) 后,容器从配置类读取扫描范围,不再靠原来的 XML 文件寻找 DaoImpl。只要扫描范围包含带组件注解的实现类,注册名称仍与获取方式对应,原来获取 Bean 并调用 save() 的职责就可以保持不变。验证纯注解切换时,应确认配置类与扫描结果完整,而不是仅凭删除 XML 后的一段提示语判断所有配置都已经迁移。
Bean的管理
Bean的作用范围
@Scope(“prototype”)即可更改
Bean的生命周期
如下代码:
实现类:
package wang.dao.impl;
import org.springframework.context.annotation.Scope;import org.springframework.stereotype.Component;import wang.dao.Dao;
import javax.annotation.PostConstruct;import javax.annotation.PreDestroy;
@Component@Scope("singleton")public class DaoImpl implements Dao { @Override public void save() { System.out.println("Dao save() ..."); }
@PostConstruct public void init() { System.out.println("init() ... "); }
@PreDestroy public void destroy() { System.out.println("destroy() ..."); }}主函数:
package wang;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;import wang.config.SpringConfig;import wang.dao.Dao;
public class AppForAnnotation { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class); Dao dao1 = ctx.getBean(Dao.class); Dao dao2 = ctx.getBean(Dao.class); System.out.println(dao1); System.out.println(dao2); ctx.close(); }}注意关闭容器或关闭钩子可以看到销毁操作
运行结果如下:
本例 DaoImpl 被设置为 singleton,主函数连续两次按 Dao 类型获取对象,因此在候选唯一的前提下,两次引用都指向同一个受管实例。@PostConstruct 标记初始化回调,ctx.close() 则触发该单例的 @PreDestroy 回调。注意主函数只是打印两次对象引用,并没有调用 save(),所以不能把业务方法提示语当作这一段代码的必然输出;对象打印出来的具体地址样式也不是判断单例的固定值。
注解开发依赖注入
@AutoWired —> 实现了引用类型的注入
注意:自动装配基于反射设计创建对象并暴力反射对应属性为私有属性初始化数据,因此无需提供setter方法
注意:自动装配建议使用无参构造方法创建对象(默认),如果不提供对应构造方法,请提供唯一的构造方法
样例代码如下:
package wang.service.impl;
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import wang.dao.Dao;import wang.service.Service;
@Servicepublic class ServiceImpl implements Service { @Autowired @Qualifier("dao") private Dao dao;
@Override public void save() { System.out.println("Service save() ..."); dao.save(); }}@Value(“变量值”) —> 实现了简单类型的注入
简单的样例代码如下:
@Servicepublic class ServiceImpl implements Service { @Value("wang") private string name;
@Override public void save() { System.out.println("Service save() ..." + name); }}那么为什么不直接将name定义为“wang”呢?为什么还要多此一举呢?
因为可以通过@Value注入properties
在配置类中加入如下注解
@PropertySource({“xxx.properties”,“xxx.properties”}) 注意:不允许使用通配符
此时可以通过@Value(“${ 属性名 }”) 访问properties中的属性
注解开发管理第三方Bean
@Bean 表示当前方法的返回值是一个Bean
@Configurationpublic class SpringConfig { //1.定义一个方法获得要管理的对象 //2.添加@Bean,表示当前方法的返回值是一个bean @Bean public Datasource dataSource() { DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName("com.mysq1.jdbc.Driver"); ds.setUr1("jdbc:mysql://localhost:3306/spring_db"); ds.setUsername("root"); ds.setPassword("1234"); return ds; }}写好当前配置文件后,在独立的配置类中导入当前配置类
方法1.扫描式 @ComponentScan({“xxx.service”, “xxx.dao”, “xxx.config”}) 不推荐
方法2.导入式 @Import(xxxconfig.class) 推荐,更为清晰
注入普通类型:
@Value("com.mysql.jdbc.Driver")private string driver;@value("jdbc:mysq1://localhost:3306/spring_db")private string url;@Value("root")private string userName;@Value("1234")private string password;使用@Value注入
注入引用类型
public Datasource dataSource() { DruidDataSource ds = new DruidDataSource(Dao dao); System.out.println(dao);}直接在形参声明即可,自动注入
XML配置对比注解配置
| 功能 | XML配置 | 注解配置 |
|---|---|---|
| 定义Bean | bean标签 • id属性 • class属性 | @Component • @Controller • @Service • @Repository<br>@ComponentScan |
| 设置依赖注入 | setter注入(set方法) • 引用类型/简单类型 构造器注入(构造方法) • 引用类型/简单类型 自动装配 | @AutoWired • @Qualifier<br>@Value |
| 配置第三方Bean | bean标签 静态工厂、实例工厂、FactoryBean | @Bean |
| 作用范围 | • scope属性 | @Scope |
| 生命周期 | 标椎接口 • init-method • destroy-method | @PostConstructor<br>@PreDestroy |