一、注解的概念
注解(Annotation),也叫元数据(Metadata),是 Java5 的新特性,JDK5引入了 Metadata 很容易的就能够调用 Annotations。注解与类、接口、枚举在同一个层次,并可以应用于包、类型、构造方法、方法、成员变量、参数、本地变量的声明中,用来对这些元素进行说明注释。
二、注解的语法与定义形式
- 以 @interface 关键字定义
- 注解包含成员,成员以无参数的方法的形式被声明。其方法名和返回值定义了该成员的名字和类型。
- 成员赋值是通过 @Annotation(name=value) 的形式。
- 注解需要标明注解的生命周期,注解的修饰目标等信息,这些信息是通过元注解实现。
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.ANNOTATION_TYPE } )
public @interface Target {
ElementType[] value();
}
三、注解的分类
3.1 元注解
meta-annotation。
负责注解其他注解的注解。JDK 1.5 及以后版本定义了 4 个标准的元注解类型:
@Documented
标记注解,用于描述其它类型的注解应该被作为被标注的程序成员的公共API,因此可以被例如 javadoc 此类的工具文档化。
@Documented @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}@Inherited
标记注解,允许子类继承父类的注解
@Inherited @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}@Retention
指注解被保留的时间长短,标明注解的生命周期。
public enum RetentionPolicy { /**
* 注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃.
* 这意味着:Annotation仅存在于编译器处理期间,编译器处理完之后,该Annotation就没用了
*/
SOURCE,
/**
* 注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期.
*/
CLASS,
/**
* 注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在,
* 保存到class对象中,可以通过反射来获取
*/
RUNTIME
}@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}@Target
标明注解的修饰目标。
// ElementType取值 public enum ElementType {
/* 类、接口(包括注解类型)或枚举 */
TYPE,
/* field属性,也包括enum常量使用的注解 */
FIELD,
/* 方法 */
METHOD,
/* 参数 */
PARAMETER,
/* 构造函数 */
CONSTRUCTOR,
/* 局部变量 */
LOCAL_VARIABLE,
/* 注解上使用的元注解 */
ANNOTATION_TYPE,
/* 包 */
PACKAGE
}
3.2 XStream
@XStreamAlias()
给类取别名。等同于
stream.alias("student", Student.class);
。@XStreamAlias("student") // define class level alias class Student {
}给属性取别名。等同于
stream.aliasField("name", Student.class, "studentName");
。class Student { @XStreamAlias("name") // define field level alias
@XStreamAsAttribute // define field as attribute
private String studentName;
}@XStreamImplicit
隐藏集合类节点。等同于
stream.addImplicitCollection(Student.class, "notes");
。class Student { @XStreamImplicit // define list as an implicit collection
private List<Note> notes = new ArrayList<Note>();
}
3.3 Hibernate
@Entity
映射实体类。将一个类声明为一个实体 bean,映射到指定的数据库表。
必须使用。
@Entity(name = "tableName") public class Student {
}- name - 可选,对应数据库中的一个表。若表名与实体类名相同,则可以省略。
@Table
映射数据库表。通常和 @Entity 配合使用,只能标注在实体的 class 定义上,表示实体对应的数据库表的信息。
可选使用。
@Entity(name = "tableName") @Table(name = "t_student", catalog = "", schema = "")
public class Student {
}- name - 可选,表示表的名称,默认的表名和实体名称一致,只有在不一致的情况下才需要指定表名
- catalog - 可选,表示 Catalog 名称,默认为 Catalog("")
- schema - 可选 , 表示 Schema 名称 , 默认为Schema("")
@Id
映射生成主键。定义了映射到数据库表的主键的属性,一个实体只能有一个属性被映射为主键,置于 getXxx() 前。
@GeneratedValue
定义主键生成策略
@SequenceGenerator
声明了一个数据库序列
@Version
定义乐观锁
@Basic
声明属性的存取策略
@Column
映射表的列
@Transient
定义暂态属性
3.4 校验
@Valid
用于验证注解是否符合要求,直接加在变量之前,在变量中添加验证信息的要求,当不符合要求时就会在方法中返回 message 的错误提示信息。
@RestController @RequestMapping("/user")
public class UserController {
@PostMapping
public User create (@Valid @RequestBody User user) {
user.setId("1");
return user;
}
}@NotBlank
public class User { private String id;
@NotBlank(message = "密码不能为空")
private String password;
}当密码为空时,@Valid 验证失败,会将 message 字段的信息返回。
其他验证信息的要求:
限制 说明 @Null 限制只能为 null @NotNull 限制必须不为 null @AssertFalse 限制必须为 false @AssertTrue 限制必须为 true @DecimalMax(value) 限制必须为一个不大于指定值的数字 @DecimalMin(value) 限制必须为一个不小于指定值的数字 @Digits(integer, fraction) 限制必须为一个小数,且整数部分的位数不能超过 integer,小数部分的位数不能超过fraction @Future 限制必须是一个将来的日期 @Past 限制必须是一个过去的日期 @Max(value) 限制必须为一个不大于指定值的数字 @Min(value) 限制必须为一个不小于指定值的数字 @Pattern(value) 限制必须符合指定的正则表达式 @Size(max,min) 限制字符长度必须在 min 到 max 之间 @Past 验证注解的元素值(日期类型)比当前时间早 @NotEmpty 验证注解的元素值不为 null 且不为空(字符串长度不为 0、集合大小不为 0) @NotBlank 验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于 @NotEmpty,@NotBlank 只应用于字符串且在比较时会去除字符串的空格 @Email 验证注解的元素值是 Email,也可以通过正则表达式和 flag 指定自定义的 email 格式 自定义验证信息
@Constraint(validatedBy = {MyConstraintValidator.class}) @Target({ELementtype.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyConstraint {
String message();
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}校验器:
public class MyConstraintValidator implements ConstraintValidator<MyConstraint, Object> { @Autowired
private UserService userService;
@Override
public void initialie(@MyConstraint constarintAnnotation) {
System.out.println("my validator init");
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
userService.getUserByUsername("seina");
System.out.println("valid");
return false;
}
}
3.5 Spring
@Controller
控制器(注入服务)。用于标注控制层,相当于 struts 中的 action 层。
@Service
服务(注入 dao)。用于标注服务层,主要用来进行业务的逻辑处理。
@Repository
实现 dao 访问。用于标注数据访问层,也可以说用于标注数据访问组件,即 DAO 组件。
@Component
把普通 pojo 实例化到 spring 容器中,相当于配置文件中的
<bean id="" class=""/>
。泛指各种组件,就是说当类不属于各种归类的时候(不属于 @Controller、@Service等时),就可以使用 @Component 来标注这个类。@Configuration
标识类可以使用 Spring IoC 容器作为 bean 定义的来源,配合 @Bean 使用。使用这两个注解就可以创建一个简单的 spring 配置类,可以用来替代相应的 xml 配置文件。
<beans> <bean id = "car" class="com.test.Car">
<property name="wheel" ref = "wheel"></property>
</bean>
<bean id = "wheel" class="com.test.Wheel"></bean>
</beans>@Configuration public class Conf {
@Bean
public Car car() {
Car car = new Car();
car.setWheel(wheel());
return car;
}
@Bean
public Wheel wheel() {
return new Wheel();
}
}@Bean
告诉 Spring,一个带有 @Bean 的注解方法将返回一个对象,该对象应该被注册为在 Spring 应用程序上下文中的 bean。
@EnableAspectJAutoProxy
开启 AOP。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/**
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}.
*/
boolean proxyTargetClass() default false;
/**
* Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
* for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
* Off by default, i.e. no guarantees that {@code AopContext} access will work.
* @since 4.3.1
*/
boolean exposeProxy() default false;
}proxyTargetClass
控制 aop 的具体实现方式。为 true 的话使用 cglib,为 false 的话使用 java 的 Proxy。exposeProxy
控制代理的暴露方式,解决内部调用不能使用代理的场景。@EnableTransactionManagement
开启 spring 事务管理。
@EnableCaching
开启 spring 缓存。
@EnableWebMvc
开启 webMvc。
@Resource 与 @Autowired 用法区别
共同点:
- @Resource 和 @Autowired 都可以作为注入属性的修饰,在接口仅有单一实现类时,两个注解的修饰效果相同,可以互相替换,不影响使用。
不同点:
- @Resource 是 Java 的注解,@Resource 有两个属性是比较重要的,name 和 type;Spring 将 @Resource 注解的 name 属性解析为 bean的名字,而 type 属性则解析为 bean 的类型。如果一个 bean 的name 和另外一个 bean 的 property 相同,就自动装配;如果一个bean 的数据类型和另外一个 bean 的 property 属性的数据类型兼容,就自动装配。
- @Autowired 是 spring 的注解,是 spring2.5 版本引入的,@Autowired 只根据 type 进行注入,不会去匹配 name。如果涉及到 type 无法辨别注入对象时,那需要依赖 @Qualifier 或 @Primary 注解一起来修饰。
3.6 SpringBoot
@ServletComponentScan
在 SpringBootApplication 上使用 @ServletComponentScan 注解后,Servlet、Filter、Listener可以直接通过 @WebServlet、@WebFilter、@WebListener 注解自动注册,无需其他代码。
@SpringBootApplication @ServletComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@WebServlet(name="TestServlet", urlPatterns="/test")
public class TestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
}
}@ComponentScan
Spring是一个依赖注入(dependency injection)框架。所有的内容都是关于 bean 的定义及其依赖关系。
ComponentScan 要做的就是告诉 Spring 从哪里找到 bean。
@ComponentScan({ "com.a.aa", "com.a.bb" }) @ComponentScan(basePackages = { "com.a.aa", "com.a.bb" })
@ComponentScan("com.a")
@ComponentScan(value = "com.a")
@ComponentScan(basePackages = {"com.a"})
@ComponentScan(basePackageClasses=Test.class)- SpringBoot 在写启动类的时候如果不使用@ComponentScan 指明对象扫描范围,默认指扫描当前启动类所在的包里的对象
- 如果当前启动类没有包,则在启动时会报错:
Your ApplicationContext is unlikely to start due to a @ComponentScan of the default package
错误,因为启动类不能直接放在 main/java 文件夹下,必须要建一个包把它放进去或者使用 @ComponentScan 指明要扫描的包; - 如果有一些 bean 所在的包,不在主类的包及其下级包,那么你需要手动加上 @ComponentScan 注解并指定那个bean 所在的包。
<context:component-scan base-package="com.a.aa, com.a.bb" />
@SpringBootApplication
@SpringBootApplication = (默认属性)@Configuration + @EnableAutoConfiguration + @ComponentScan
@SpringBootApplication public class ApplicationMain {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}@EnableAutoConfiguration
能够自动配置 spring 的上下文,试图猜测和配置你想要的 bean 类,通常会自动根据你的类路径和你的 bean 定义自动配置。