Java和Spring常用注解
Bean标识
@component和@service
在Spring框架中,@Component
和@Service
都是用来将一个Java类标记为Spring容器中的一个组件。不过,在实际开发中,@Service通常用于标记业务层的Bean,而@Component
则更为通用,可以用于标记任意层的Bean。
具体而言,@Component
表示通用的组件,可以用在任何层次。它是一个比较抽象的概念,可以用于标记任何需要被Spring容器管理的组件类。而@Service
则表示服务层组件,用于标记服务层(业务层)的Bean。所以,@Service
通常和@Repository
(用于标记DAO层数据访问对象)一起使用,一起组成完整的MVC架构中的三层结构。
@Repository
用于标识一个类是 DAO(Data Access Object)组件。DAO 组件通常用于访问数据库或其他持久化存储机制,它们封装了对数据的访问和操作,提供了一种面向对象的方式来访问数据。
@Repository
注解本质上是 @Component
注解的一个特化版本,它们的作用是相同的。@Repository
注解的作用是为了更好地表达 DAO 组件的含义,使代码更加清晰易懂。
@Configuration
@Configuration
主要用于标注一个Java类是Spring的配置类,Configuration注释类表明其主要目的是作为bean定义的源。
主要用法:
1.声明bean
在@Configuration类中使用@Bean注解,通过方法返回值来声明一个Bean,并将其加入到Spring容器中。
@Configuration
public class AppConfig {
@Bean
public MyBean myBean() {
return new MyBean();
}
}
@Configuration标记该类为配置类,@Bean标记myBean()方法返回的对象MyBean为Spring容器管理的组件。
2.引入配置
- 使用@Import或注解,将其它配置类或配置文件中的bean加入到当前配置类中,以便在当前类中引用。
@Configuration
public class DatabaseConfig {
@Bean
public DataSource dataSource() {
// 创建 DataSource Bean
}
}
@Configuration
@Import(DatabaseConfig.class)
public class AppConfig {
// 此处可以直接使用 DataSource:
@Autowired
DataSource dataSource;
@Bean
public MyBean myBean() {
// 使用 DataSource 来创建 MyBean Bean
}
}
DatabaseConfig 中定义了一个 DataSource 的 Bean,@Import 注解被用来将其引入到 AppConfig 中。这样,在 AppConfig 中可以直接使用 dataSource Bean。
- 除了 @Import,我们还可以使用 @ImportResource 来引入其他 XML 文件中的配置。
@Configuration
@ImportResource({ "classpath:spring/context-config.xml", "classpath:spring/dao-config.xml" })
public class AppConfig {
// ...
}
- 使用 @Configuration 注解来标记这个类是一个配置类,然后使用 @Value 注解来从配置文件中读取相关的配置。
@Configuration
public class DataAccessConfig {
@Value("${jdbc.driver-class-name}")
private String driverClassName;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
@Bean
public UserDao userDao() {
return new UserDaoImpl(jdbcTemplate());
}
// 其他 DAO 相关 Bean 的定义
// ...
}
@interface
Java中的@interface是用于声明注解的关键字。注解是Java语言提供的一种元数据机制,它可以提供给代码的编写者和阅读者更多的信息,也可以标识代码中特定的语义。
使用@interface关键字声明的注解本质上是一种特殊的接口定义,它可以包含属性、方法、默认值等信息。注解可以被应用于类、方法、字段和其他元素上,通过注解的方式对这些元素进行标记,随后可以在编译时、类加载时、运行时等各种时期通过反射机制读取注解信息,从而实现对代码的一些非侵入式操作。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
String value();
}
public class MyClass {
@MyAnnotation("Hello World")
public void sayHello() {
System.out.println("Hello World");
}
}
在该例子中,自定义了一个注解MyAnnotation,在MyClass中的sayHello方法上使用了该注解。这里的注解可以提供一些有用的元数据,如"value()"属性,它可以被注入到对应的方法中。
Bean注入
@resource
在Spring框架中,@Resource和@Autowired都可以用于将一个Bean注入到另一个Bean中,不过它们有一些区别。
@Resource
@Resource是Java标准注解,是JDK提供的,但是Spring支持该注解的注入,可以用来注入其他Bean,它是按照名称
进行自动装配的。它提供了两个属性:name和type。
当使用name属性时,它会按照指定的名称查找对应的Bean进行注入;当使用type属性时,它会按照指定的类型查找对应的Bean进行注入。
@Service("userService")
当@Resource注解需要装配的Bean在容器中有多个与之对应的Bean名称时,会抛出NoSuchBeanDefinitionException异常。
例如,假设有两个实现UserService接口的类:
@Service("userService1")
public class UserServiceImpl1 implements UserService {
}
@Service("userService2")
public class UserServiceImpl2 implements UserService {
}
在另一个需要依赖一个UserService的类中,如果使用@Resource注解进行注入:
@Service
public class SomeServiceImpl implements SomeService {
@Resource
private UserService userService;
}
在尝试装配UserService时,由于容器中存在多个与之对应的Bean名称,会抛出NoSuchBeanDefinitionException异常。此时,我们需要使用@Qualifier注解或者在@Bean注解中指定Bean名称来解决装配冲突。
方法1: 使用@Qualifier注解指定具体的Bean名称:
@Service
public class SomeServiceImpl implements SomeService {
@Resource
@Qualifier("userService1")
private UserService userService;
}
或
@Service
public class SomeServiceImpl implements SomeService {
@Resource(name="userService")
private UserService userService;
}
方法2: 在@Bean注解中指定Bean名称:
@Configuration
public class AppConfig {
@Bean(name="userService")
public UserService userService() {
return new UserServiceImpl1();
}
@Bean(name="anotherUserService")
public UserService anotherUserService() {
return new UserServiceImpl2();
}
}
@Resource的装配顺序:
- 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
- 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
- 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
- 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配。如果没有匹配,则回退为一个原始类型(UserDao)进行匹配,如果匹配则自动装配。(先Name后type)
Resource注解在字段上,这个注解是属于J2EE的,减少了与spring的耦合。可以指定是通过 name 还是 type 的注入方式,而@Autowired注解本身自己是不能实现这个效果的,要和@Qualifier一起用才可以!
@Autowired
@Autowired
是Spring框架特有的注解,也是按照类型(by Type)
进行自动装配的。它默认按照类型查找对应的Bean,并将它注入到需要依赖的Bean中。如果有多个同一类型的Bean存在,它还可以使用Qualifier注解指定需要注入的Bean名称(by Name)。
更具体地说,当一个Bean中出现了@Autowired注解,容器会自动完成以下步骤:
- 搜索容器中所有匹配于指定类型的Bean;
- 如果只找到一个与指定类型匹配的Bean,则将此Bean自动注入到当前需要的Bean中;
- 如果找到多个与指定类型匹配的Bean,则从中选择一个合适的Bean自动注入。
当@Autowired注解需要装配的Bean在容器中有多个与之对应的Bean类型时,Spring会尝试按类型进行自动装配。如果根据类型无法确定要装配哪个Bean时,会抛出NoUniqueBeanDefinitionException异常。
此时,我们需要使用@Qualifier注解或者在@Bean注解中指定Bean名称来解决装配冲突。
方法1: @Qualifier
public class TestServiceImpl() {
@Autowired
@Qualifier("userDaoImpl1") // 指定哪一个实现类
private UserDao userDao;
...
}
方法2: @Primary
使用@Primary注解指定一个进行注入!!!
@Primary
@Mapper
public class UserDaoImpl01 implements UserDao {
...
}
@Mapper
public class UserDaoImpl02 implements UserDao {
...
}
区别
与@Resource不同,@Autowired是Spring框架特有的注解,而且它可以使用更加灵活的方式进行关联。@Autowired是按照类型进行自动装配的,可以与Qualifier注解一起使用进行名称匹配,并且它支持@Primary注解,用于指定默认的Bean。此外,@Autowired注解还支持使用构造函数注入、Setter方法注入、成员变量注入等不同的方式。
而@Resource则是Java标准注解,虽然它也可以进行自动装配,但只支持按照名称和类型查找Bean,并且它没有像@Autowired那样支持更加灵活的@Autowired注释组合操作。
控制加载顺序
@PostConstruct
通常用于标记一个方法,它表示该方法在类实例化之后(通过构造函数创建对象之后)立即执行。
这是一种常见的初始化模式,用于设置 bean 的初始状态或执行一些必要的启动逻辑。
需要注意的是,@PostConstruct
方法只会被调用一次,即在 bean 初始化时。如果后续需要重新初始化规则,需要另外提供一个方法来实现。
@FunctionalInterface 函数式接口
- 必须是一个接口(interface)。
- 有且仅有一个抽象方法(允许包含默认方法或静态方法)。
- 使用
@FunctionalInterface
注解标记,编译器会强制校验是否符合条件。
详见:Java常用注解–@FunctionalInterface 函数式接口
Web MVC
@RequestMapping
将Web请求与请求处理类中的方法进行映射。
@RequestMapping注解拥有以下的六个配置属性:
- value:映射的请求URL或者其别名
- method:兼容HTTP的方法名
- params:根据HTTP参数的存在、缺省或值对请求进行过滤
- header:根据HTTP Header的存在、缺省或值对请求进行过滤
- consume:设定在HTTP请求正文中允许使用的媒体类型
- product:在HTTP响应体中允许使用的媒体类型
提示:在使用@RequestMapping之前,请求处理类还需要使用@Controller
或@RestController
进行标记
@controller
@RequestMapping(value=" /demo")
public class DemoController{
@RequestMapping(value=" /home" ,method=RequestMethod.GET)
public String home(){
return "/home" ;
}
}
@RequestMapping可以标记方法,也可以标记类。
@GetMapping
是@RequestMapping(method=RequestMethod.GET)的快捷方式
@PostMapping
是@RequestMapping(method=RequestMethod.POST)的快捷方式
@RequestBody
可以将请求主体中的参数绑定到一个对象中,此外,还可以通过@Valid注解对请求主体中的参数进行校验。
@RequestController
@RequestMapping("/api/v1")
public class UserController{
@Autowired
private UserService userService;
@PostMapping("/users")
public User createUser@Valid @RequestBody User user){
return userService.save(user);
}
}
@Data,@Setter和@Getter
@Data注解是Lombok提供的一个注解,它会自动为类生成一些常用方法,如@Getter、@Setter、@ToString、@EqualsAndHashCode和@RequiredArgsConstructor等,它们的作用如下:
@Getter和@Setter注解会自动生成属性的get和set方法,使得我们在使用属性时不需要手动编写这些方法。
@ToString注解会自动生成toString方法。
@EqualsAndHashCode注解会自动生成equals和hashCode方法。
@RequiredArgsConstructor注解会自动生成一个包含所有final和@NonNull属性的构造方法。
而使用@Getter和@Setter注解则只会自动生成get和set方法,不能自动生成其他方法,如@ToString、@EqualsAndHashCode和@RequiredArgsConstructor等。
例如下面的代码:
@Data
public class Person {
private String name;
private int age;
}
使用@Data注解可以等价于以下代码:
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
@EqualsAndHashCode
@EqualsAndHashCode是Lombok提供的一个注解,可以自动为类生成equals和hashCode方法。equals和hashCode方法是用于判断对象是否相等和将对象插入散列表中时的重要方法,通过使用@EqualsAndHashCode注解可以避免手动重写equals和hashCode方法。
@EqualsAndHashCode注解默认对所有属性进行比较,如果只想对某些属性进行比较,也可以使用exclude和of属性来指定,比如:
@Data
@EqualsAndHashCode(exclude = "id")
public class User{
private Long id;
private String name;
private Integer age;
}
这样,equals和hashCode方法就会忽略id属性,只比较name和age属性了。
@Profile
Java @Profile是Spring框架中所提供的一种条件注解。通过使用@Profile注解,可以为不同的环境(例如开发环境和生产环境)配置不同的bean。
使用@Profile注解需要以下两个步骤:
-
标记bean:在需要标记的类或方法上添加@Profile注解,并指定其所属的环境,例如
@Profile("dev")
注解表示该类或方法为开发环境下的bean。 -
激活配置:在Spring的配置文件中,通过指定激活的环境,从而加载对应环境下的配置。例如,使用spring.profiles.active属性指定运行环境为开发环境:-Dspring.profiles.active=“dev”。
在Spring Boot中,可以通过在application.properties或application.yml文件中设置spring.profiles.active属性来激活对应的配置文件。例如,当spring.profiles.active属性设置为"dev"时,Spring Boot会加载application-dev.properties或application-dev.yml配置文件中的配置信息。
通过使用@Profile注解,可以使开发者轻松地将不同的bean和配置文件分离,并为不同的环境提供不同的配置信息,从而提高应用程序的可配置性和可移植性。