用来替代更加重量级的企业级 Java 技术 相对 EJB(Enterprise JavaBean, 企业级 JavaBean),增强了 POJO(Plain Old Java object)功能,使其具备了之前只有 EJB 和 其他企业级 Java 规范才有的功能。 现在 EJB 也采用了 依赖注入(Dependency Injection,DI)和面向切面编程(Aspect-Oriented Programming,AOP)。
DI 让互相协作的软件组件保持松散耦合 没有耦合的代码什么做不了 三种注入方式:
field注入构造器注入setter注入 @Controller public class PageController { @Autowired private PageService pageService; //简单的使用例子 public List<Page> listFoo() { return pageService.list(); } }AOP 允许你将遍布应用各处的功能分类出来形成可重用的组件
Spring 的 JDBC 和 DAO(Data Access Object)模块抽象了样板式代码,使数据库代码变得简单明了,还可以避免因数据库资源失败而引发的问题。 Spring 的 ORM(Object-Relational Mapping)模块建立在对 DAO 的支持上,为多个 ORM 框架提供了以重构建 DAO 的简便方式,对许多流行的 ORM 框架进行了集成,包括 Hibernate、Java Persisternce API、Java Data Object 和 iBATIS SQL Maps,其事务管理支持所有 ORM 和 JDBC。
提供 MVC(Model View Controller)模式 提供暴露和使用 REST API 的良好支持
表明该类会作为组件类,告知 Spring 要为这个类创建 bean 不过组件扫描默认使不启用的,需要显示配置 Spring 命令其寻找带有 @Component 注解的类,并为其创建 bean。 通过 @CompoentScan 扫描
//将扫描的 bean 标识为 use。 @Component("use") public class Page implements ComDisc{ ... } //扫描多个包 包名 @Configuration @ComponentScan(basePackages={"record", "video"}) public class Page{ ... } //扫描多个包中的类或接口 @Configuration @ComponentScan(basePackagesClasses={record.class, video.class}) public class Page{ ... }@Autowired 注解 用在构造器和属性的 Setter 方法上
@Autowired public void setRecord(Record record) { this.record = record; }若没有匹配 bean,Spring 可能会抛出异常,可将 @Autowired 的 required 属性设置为 false。
@Autowired(required = false) public void setRecord(Record record) { this.record = record; }@Inject 是 java 依赖注入规范,@Autowired 是 Spring 特有的。
@Configuration 注解 表明该类是个配置类
@Bean 注解 告诉 Spring 这个方法要返回一个对象,该对象要注册为 Spring 应用上下文中的 bean,且可以指定一个名字。
@Bean(name="lonelyHeartsCludBand") public Page record() { return new Record(); }环境和 profile 使用嵌入式数据库
@Bean(destroyMethod = "record") public DataSource dataSource() { return new EmbeddedDatabaseBuilder() .addScript("classpath: schema.sql") .addScript("classpath: test-data.sql") .build(); }EmbeddedDatabaseBuilder 可搭建一个嵌入式的 Hypersonic 数据库,其模式(schema)定义在 schema.sql 中, 测试数据通过 test-data.sql 加载。 EmbeddedDatabaseBuilder 创建的 DataSource 适合开发环境,但是不适合生产环境 JNDI 管理的 DataSource 更加适合生产环境,对于简单的集成和开发测试环境来说会带来不必要的复杂性。 QA 环境中可以选择不同的 DataSource 配置,配置 Commons DBCP 连接池。
@Profile 注解指定某个 bean 属于哪个 profile 只有在 development profile 激活时才会创建
@Configuration public class DataSourceConfiguration { @Profile("development") @Bean public DataSource embeddedDataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .addScript("classpath*:schema.sql") .addScript("classpath*:test-data.sql") .build(); } @Profile("qa") @Bean public BasicDataSource basicDataSource() { BasicDataSource ds = new BasicDataSource(); ds.setDriverClassName("org.h2.Driver"); ds.setUrl("jdbc:h2:tcp://localhost/~/spitter"); ds.setUsername("sa"); ds.setPassword(""); ds.setInitialSize(5); //初始大小 ds.setMaxTotal(10); //数据库连接池大小 return ds; } @Profile("production") @Bean public DataSource dataSource() { JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean(); jndiObjectFactoryBean.setJndiName("/jdbc/SpittrDS"); jndiObjectFactoryBean.setResourceRef(true); jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class); return (DataSource)jndiObjectFactoryBean.getObject(); } }@Conditional 注解 用于带有 @Bean 的注解的方法上,形成条件化的 bean,如果给定的条件计算结果为 true,就创建,反之忽略 bean。
@Profile 基于 @Conditional 和 Condition 实现,其本身也使用了 @Conditional 注解
@Primary 注解 告诉 Spring 最喜欢的方案,声明首选 bean。
@Qualifier 注解 使用限定符的主要方式,可以和@Autowired 和 @Inject 协同使用,在注入的时候指定想要注入的是哪个 bean。
@Autowired @Qualifier("iceCream") public void setDessert(Dessert dessert) { this.dessert = dessert; }注入外部的值 @PropertySource 注解
//声明属性源 @PropertySource("classpath:/com/soundsystem/app.properties") public class test(){ ... } //这个属性文件或加载到 Spring 的 Environment 中,稍后可以从这里检索属性。定义切面 @Aspect 注解 定义切面类
@Aspect public class Audience { //这是表演之前 @Before("execution(* com.spring.learn.index.Performance.perform(..))") public void silenceCellPhones(){ System.out.println("观众的手机静音"); } //表演之前 @Before("execution(* com.spring.learn.index.Performance.perform(..))") public void takeSeats() { System.out.println("观众落座"); } //表演之后 @AfterReturning("execution(* com.spring.learn.index.Performance.perform(..))") public void applause() { System.out.println("掌声雷动"); } //表演失败 @AfterThrowing("execution(* com.spring.learn.index.Performance.perform(..))") public void demandRefund() { System.out.println("要求退款"); } } 前置通知(@Before):通知方法在目标方法调用之前执行。后置通知(@After):通知方法在目标方法返回或抛出异常后调用。返回通知(@AfterReturning):通知方法在目标方法返回后调用。异常通知(@AfterThrowing):通知方法在目标方法抛出异常之后调用。环绕通知(@Around):通知方法在目标方法封装起来。@Pointcut @Pointcut 所注释的值是一个切点表达式
@Aspect public class Audience { @Pointcut("execution(* com.spring.learn.index.Performance.perform(..))") public void performance(){} //这是表演之前 @Before() public void silenceCellPhones("performance()"){ System.out.println("观众的手机静音"); } //表演之前 @Before("performance()") public void takeSeats() { System.out.println("观众落座"); } //表演之后 @AfterReturning("performance()") public void applause() { System.out.println("掌声雷动"); } //表演失败 @AfterThrowing("performance()") public void demandRefund() { System.out.println("要求退款"); } }参考文献: Spring 实战(第4版) [美] Craig Walls 著 张卫滨 译 人民邮电出版社
