基于注解的配置
从 Spring 2.5 开始就可以使用注解来配置依赖注入。而不是采用 XML 来描述一个 bean 连线,你可以使用相关类,方法或字段声明的注解,将 bean 配置移动到组件类本身。
在 XML 注入之前进行注解注入,因此后者的配置将通过两种方式的属性连线被前者重写。
注解连线在默认情况下在 Spring 容器中不打开。因此,在可以使用基于注解的连线之前,我们将需要在我们的 Spring 配置文件中启用它。所以如果你想在 Spring 应用程序中使用的任何注解,可以考虑到下面的配置文件。一旦被配置后,你就可以开始注解你的代码,表明 Spring 应该自动连接值到属性,方法和构造函数。
<?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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<!-- bean definitions go here -->
</beans>
序号 | 分类 |
---|---|
1 | 用于创建bean对象 |
2 | 用于注入数据的 |
3 | 用于改变作用范围的 |
4 | 和生命周期相关的 |
5 | Spring的新注解 |
用于创建bean对象
@Component
- 作用:就相当于配置了一个bean标签
- 它能出现的位置:类上面
- 属性:value。含义是指定bean的id。当不写时,它有默认值,默认值是:当前类的短名首字母改小写。
- 由此衍生的三个注解:
@Controller:一般用于表现层的注解
@Service:一般用于业务层
@Repository:一般用于持久层
(它们和@Component的作用及属性都一模一样)
用于注入数据
注解 | 作用 | 属性 |
---|---|---|
@Autowired | 自动按照类型注入,只要有唯一的类型匹配就能注入成功。如果注入的bean在容器中类型不唯一时,它会把变量名称作为bean的id,在容器中查找,找到后也能注入成功。如果没有找到一致的bean的id,则报错 | |
@Qualifier | 在自动按照类型注入的基础上,再按照bean的id注入。它在给类成员注入数据时不能独立使用。但是在给方法的形参注入数据时,可以独立使用。 | value:用于指定bean的id |
@Resource | 直接按照bean的id注入 | name:用于指定bean的id |
@Value | 用于注入基本类型和String类型数据。它可以借助spring的el表达式读取properties文件中的配置 | value:用于指定要注入的数据 |
前三个注解都是用于注入其他bean类型的,用于注入基本类型和String类型需要使用Value
下面显示的是使用 @Qualifier 注释的一个示例
Student.java 文件的内容:
package com.tutorialspoint;
public class Student {
private Integer age;
private String name;
public void setAge(Integer age) {
this.age = age;
}
public Integer getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Profile.java 文件的内容:
package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class Profile {
@Autowired
@Qualifier("student1")
private Student student;
public Profile(){
System.out.println("Inside Profile constructor." );
}
public void printAge() {
System.out.println("Age : " + student.getAge() );
}
public void printName() {
System.out.println("Name : " + student.getName() );
}
}
MainApp.java 文件的内容:
package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
Profile profile = (Profile) context.getBean("profile");
profile.printAge();
profile.printName();
}
}
考虑下面配置文件 Beans.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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<!-- Definition for profile bean -->
<bean id="profile" class="com.tutorialspoint.Profile">
</bean>
<!-- Definition for student1 bean -->
<bean id="student1" class="com.tutorialspoint.Student">
<property name="name" value="Zara" />
<property name="age" value="11"/>
</bean>
<!-- Definition for student2 bean -->
<bean id="student2" class="com.tutorialspoint.Student">
<property name="name" value="Nuha" />
<property name="age" value="2"/>
</bean>
</beans>
如果你的应用程序一切都正常的话,这将会输出以下消息:
Inside Profile constructor.
Age : 11
Name : Zara
用于改变作用范围的
@Scope
- 作用:用于改变bean的作用范围。
- 属性:value:用于指定范围的取值。
取值和xml中scope属性的取值是一样的。singleton,prototype,request,session globalsession
和生命周期有关的(了解):
@PostConstruct
作用:用于指定初始化方法。
@PreDestroy
作用:用于指定销毁方法
关于Spring注解和XML的选择问题
- 注解的优势:配置简单,维护方便(我们找到类,就相当于找到了对应的配置)。
- XML的优势:修改时,不用改源码。不涉及重新编译和部署。
- Spring管理bean方式的比较:
Spring基于Java的配置(纯注解配置)
我们发现,之所以我们现在离不开xml配置文件,是因为我们有一句很关键的配置:
<!-- 告知spring框架在,读取配置文件,创建容器时,扫描注解,依据注解创建对象,并存入容器中 -->
<context:component-scan base-package="com.itheima"></context:component-scan>
如果它要也能用注解配置,那么我们就可以脱离xml文件了。
/**
* 客户的业务层实现类
*/
@Configuration//表明当前类是一个配置类
@ComponentScan(basePackages = "com.itheima")//配置要扫描的包
public class SpringConfiguration {
}
//那么新的问题又来了,我们如何获取容器呢?
public class Client {
public static void main(String[] args) {
//1.获取容器:由于我们已经没有了xml文件,所以再用读取xml方式就不能用了。
//这时需要指定加载哪个类上的注解
ApplicationContext ac =
new AnnotationConfigApplicationContext(SpringConfiguration.class);
//2.根据id获取对象
ICustomerService cs = (ICustomerService) ac.getBean("customerService");
cs.saveCustomer();
}
}
新注解说明
@Configuration
- 作用:用于指定当前类是一个spring配置类,当创建容器时会从该类上加载注解。获取容器时需要使用AnnotationApplicationContext(有@Configuration注解的类.class)。
- 属性: value:用于指定配置类的字节码
@ComponentScan
- 作用:用于指定spring在初始化容器时要扫描的包。作用和在spring的xml配置文件中的:
<context:component-scan base-package="com.itheima"/>
是一样的。 - 属性:basePackages:用于指定要扫描的包。和该注解中的value属性作用一样。
@PropertySource
- 作用:用于加载.properties文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到properties配置文件中,就可以使用此注解指定properties配置文件的位置。
- 属性:value []:用于指定properties文件位置。如果是在类路径下,需要写上classpath:
@Import
- 作用:用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration注解。当然,写上也没问题。
- 属性: value[]:用于指定其他配置类的字节码。
- 示例代码:
@Configuration
@ComponentScan(basePackages = "cn.itcast.spring")
@Import({ Configuration_B.class})
public class Configuration_A {
}
@Configuration
@PropertySource("classpath:info.properties")
public class Configuration_B {
}
@Bean
-
作用:该注解只能写在方法上,表明使用此方法创建一个对象,并且放入spring容器。它就相当于我们之前在xml配置中介绍的factory-bean和factory-method。
-
属性:name:给当前@Bean注解方法创建的对象指定一个名称(即bean的id)。
@Configuration 和 @Bean 注解
带有 @Configuration 的注解类表示这个类可以使用 Spring IoC 容器作为 bean 定义的来源。@Bean 注解告诉 Spring,一个带有 @Bean 的注解方法将返回一个对象,该对象应该被注册为在 Spring 应用程序上下文中的 bean(它是把方法的返回值存入spring容器中。该注解有一个属性,name:用于指定bean的id。当不指定时它有默认值,默认值是方法的名称)。最简单可行的 @Configuration 类如下所示:
package com.tutorialspoint;
import org.springframework.context.annotation.*;
@Configuration
public class HelloWorldConfig {
@Bean //它是把方法的返回值存入spring容器中。该注解有一个属性,name:用于指定bean的id。当不指定时它有默认值,默认值是方法的名称。
public HelloWorld helloWorld(){
return new HelloWorld();
}
}
上面的代码将等同于下面的 XML 配置:
<beans>
<bean id="helloWorld" class="com.tutorialspoint.HelloWorld" />
</beans>
在这里,带有 @Bean 注解的方法名称作为 bean 的 ID,它创建并返回实际的 bean。你的配置类可以声明多个 @Bean。一旦定义了配置类,你就可以使用 AnnotationConfigApplicationContext 来加载并把他们提供给 Spring 容器,如下所示:
public static void main(String[] args) {
ApplicationContext ctx =
new AnnotationConfigApplicationContext(HelloWorldConfig.class);
HelloWorld helloWorld = ctx.getBean(HelloWorld.class);
helloWorld.setMessage("Hello World!");
helloWorld.getMessage();
}
你可以加载各种配置类,如下所示:
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class, OtherConfig.class);
ctx.register(AdditionalConfig.class);
ctx.refresh();
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}