在Spring框架中,@Component和@Service都是用来将一个Java类标记为Spring容器中的一个组件。不过,在实际开发中,@Service通常用于标记业务层的Bean,而@Component则更为通用,可以用于标记任意层的Bean。
具体而言,@Component表示通用的组件,可以用在任何层次。它是一个比较抽象的概念,可以用于标记任何需要被Spring容器管理的组件类。而@Service则表示服务层组件,用于标记服务层(业务层)的Bean。所以,@Service通常和@Repository(用于标记DAO层数据访问对象)一起使用,一起组成完整的MVC架构中的三层结构。
在Spring框架中,@Resource和@Autowired都可以用于将一个Bean注入到另一个Bean中,不过它们有一些区别。
@Resource
@Resource是Java标准注解,也被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名称来解决装配冲突。
@Service
public class SomeServiceImpl implements SomeService {
@Resource
@Qualifier("userService1")
private UserService userService;
}
或
@Service
public class SomeServiceImpl implements SomeService {
@Resource(name="userService")
private UserService userService;
}
@Configuration
public class AppConfig {
@Bean(name="userService")
public UserService userService() {
return new UserServiceImpl1();
}
@Bean(name="anotherUserService")
public UserService anotherUserService() {
return new UserServiceImpl2();
}
}
@Autowired
@Autowired是Spring框架特有的注解,也是按照类型
进行自动装配的。它默认按照类型查找对应的Bean,并将它注入到需要依赖的Bean中。如果有多个同一类型的Bean存在,它还可以使用Qualifier注解指定需要注入的Bean名称。
更具体地说,当一个Bean中出现了@Autowired注解,容器会自动完成以下步骤:
同样,当@Autowired注解需要装配的Bean在容器中有多个与之对应的Bean类型时,Spring会尝试按类型进行自动装配。如果根据类型无法确定要装配哪个Bean时,会抛出NoUniqueBeanDefinitionException异常。此时,我们需要使用@Qualifier注解或者在@Bean注解中指定Bean名称来解决装配冲突。
区别
与@Resource不同,@Autowired是Spring框架特有的注解,而且它可以使用更加灵活的方式进行关联。@Autowired是按照类型进行自动装配的,可以与Qualifier注解一起使用进行名称匹配,并且它支持@Primary注解,用于指定默认的Bean。此外,@Autowired注解还支持使用构造函数注入、Setter方法注入、成员变量注入等不同的方式。
而@Resource则是Java标准注解,虽然它也可以进行自动装配,但只支持按照名称和类型查找Bean,并且它没有像@Autowired那样支持更加灵活的@Autowired注释组合操作。
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()"属性,它可以被注入到对应的方法中。
@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是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属性了。