JAVA注解梳理

**

1. Java层级

在这里插入图片描述

MVC设计模式:M(model)指模型,V(view)指视图层,C(controller)指控制层。
M代表模型一般指service和DAO;
view代表视图一般指页面eg:jsp,html ftl等;
C代表控制器,比如springMVC 中的controller或struts2中的action 。

2.@SpringBootApplication

SpringBoot 的诞生就是为了简化 Spring 中繁琐的 XML 配置,其本质依然是 Spring 框架,使用 SpringBoot 之后可以不使用任何 XML 配置来启动一个服务,使得我们在使用微服务架构时可以更加快速地建立一个应用。

SpringBoot 具有以下特点:

创建独立的 Spring 应用。
直接嵌入了 Tomcat、Jetty 或 Undertow(不需要部署 WAR 文件)。
提供了固定的配置来简化配置。
尽可能地自动配置 Spring 和第三方库。
提供可用于生产的特性,如度量、运行状况检查和外部化配置。
完全不需要生成代码,也不需要 XML 配置。

SpringBoot 这些特点中最重要的两条就是约定优于配置自动装配

约定优于配置

SpringBoot 的约定由于配置主要体现在以下方面:

maven 项目的配置文件存放在 resources 资源目录下。
maven 项目默认编译后的文件放于 target 目录。
maven项目默认打包成 jar 格式。
配置文件默认为 application.yml 或者 application.yaml 或者application.properties。
默认通过配置文件 spring.profiles.active 来激活配置。
springboot的自动装配实际上就是为了从spring.factories文件中获取到对应的需要进行自动装配的类,并生成相应的Bean对象,然后将它们交给spring容器来帮我们进行管理。下面详细分析。

自动装配

自动装配是 SpringBoot 的核心,只要引入一个 starter 组件依赖就能实现自动装配
相比较于传统的 Spring 应用,搭建一个 SpringBoot 应用,只需要引入一个注解 @SpringBootApplication,就可以成功运行。

3.注册一个bean到IOC容器中

注解本质上就是一个类,开发中我们可以使用注解取代xml配置文件。

3.1 @Bean

Spring的@Bean注解作用于方法,将方法返回值作为bean自动装配到IOC容器中的。方法名作为组件的id,给容器中添加组件,返回组件在容器中的实例。用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理。产生这个Bean对象的方法Spring只会调用一次,随后这个Spring将会将这个Bean对象放在自己的IOC容器中。
SpringIOC 容器管理一个或者多个bean,这些bean都需要在@Configuration注解下进行创建,在一个方法上使用@Bean注解就表明这个方法需要交给Spring进行管理。
@Bean注解和在xml里面用Bean标签存储一样,会在加载xml上下文时(启动类中 ApplicationContext applicationContext = new ClassPathXmlApplicationContext(“spring-config.xml”);这一条代码)就自动执行,并且只会执行一次。

@Controller
public class UserController {
    @Bean
    public StudentController sa() {
        return new StudentController();
    }
}

@Bean通常被用在@Configuration注解的类中的方法上。这其实就是替换xml配置文件的另一种写法:

//配置类
@Configuration
public class MyConfig {
    @Bean
    public UserService userService() {
        return new UserServiceImpl();
    }
}
//xml配置文件
<beans>
	<bean id="userService" class="com.gzc.UserServiceImpl">
	</bean>
</beans>

3.2 @Component & @Controller & @Service & @Repository

@Component

@component的作用就是实现bean的注入,作用于类加在类上后,项目启动容器初始化时,就会通过扫描类路径把这个bean注入到IOC容器中。

在Java的web开发中,提供3个@Component注解衍生注解(功能与@component一样,只是在MVC模式上表示的层不一样)分别是:
1、@Controller 控制器(注入服务) 用于标注控制层,相当于struts中的action层。
2、@Service 服务(注入dao) 用于标注服务层service层,主要用来进行业务的逻辑处理
3、@Repository(实现dao访问) 用于标注数据访问层view层,也可以说用于标注数据访问组件,即DAO组件
而@Component泛指各种组件,就是说当我们的类不属于各种归类的时候(不属于@Controller、@Services等的时候),我们就可以使用@Component来标注这个类。
当一个 Bean 被自动检测到时,会根据那个扫描器的 BeanNameGenerator 策略生成它的 bean名称。默认情况下,对于包含 name 属性的 @Component、@Repository、 @Service 和@Controller,会把 name 取值作为 Bean 的名字。如果这个注解不包含 name值或是其他被自定义过滤器发现的组件,默认 Bean 名称会是小写开头的非限定类名。

@Repository

@Repository用于将数据访问层 (DAO 层 ) 的类标识为 Spring Bean。具体只需将该注解标注在 DAO类上即可。就不再需要在 XML 中显式使用 进行Bean 的配置。Spring 在容器初始化时将自动扫描 base-package 指定的包及其子包下的所有 class文件,所有标注了 @Repository 的类都将被注册为 Spring Bean。
为了让 Spring 能够扫描类路径中的类并识别出 @Repository 注解,需要在 XML 配置文件中启用Bean 的自动扫描功能,这可以通过context:component-scan/实现。如下所示:
在这里插入图片描述
@Repository 标注在 DAO 类上是因为该注解的作用不只是将类识别为Bean,同时它还能将所标注的类中抛出的数据访问异常封装为 Spring 的数据访问异常类型。 Spring本身提供了一个丰富的并且是与具体的数据访问技术无关的数据访问异常结构,用于封装不同的持久层框架抛出的异常,使得异常独立于底层的框架。

@Service

@Service注解用于类上,标记当前类是一个service类,加上该注解会将当前类自动注入到spring容器中,不需要再在applicationContext.xml文件定义bean了。
在这里插入图片描述

@Service(“serviceName”)注解相当于applicationContext.xml配置文件中配置的,表示给当前类命名一个别名,方便注入到其他需要用到的类中。
@Service注解也可以不指定serviceName,如果不指定相当于,com.study.service.ServiceName就是这个类的全限定名,不加的话,默认别名就是当前类名,但是首字母小写。
在调用该service的时候只需要将该类注入接口中即可。

@Controller

@Controller标识的类,该类代表控制器类(控制层/表现层)。
这里控制层里面的每个方法,都可以去调用@Service标识的类(业务逻辑层),
@Service标识的类中的方法可以继续调用@Resposity标识的接口实现类(Dao层/持久层)。

4.@Autowired & ## @Resource 自动装配对象

@Autowired

IOC操作Bean管理:(1)spring创建对象 (2)spring注入属性。
在一个类上标注@Service或@Controller或@Component或@Repository注解之后,spring的组件扫描就会自动发现它,并且会将其根据无参构造函数初始化为spring应用上下文中的bean。
@Autowired可以标注在属性上、方法上和构造器上,默认根据属性类型实现Bean的依赖注入(ByType方式)。spring自动将匹配到的属性值进行注入,然后就可以使用这个属性对象的方法。也就是可以理解为,自动注入该类的实例化对象,后续就可以直接调用方法。
在这里插入图片描述
当标注的属性是接口时,其实注入的是这个接口的实现类, 如果这个接口有多个实现类,只使用@Autowired就会报错,因为它默认是根据类型找,然后就会找到多个实现类bean,所有就不知道要注入哪个。然后它就会根据属性名去找。所以如果有多个实现类可以配合@Qualifier(value=“类名”)来使用 (是根据名称ByName来进行注入的)
![在这里插入图片描述](https://img-blog.csdnimg.cn/4a74b25864f54e1dbf91c34a7fa1a09c.png
在这里插入图片描述在这里插入图片描述

注:Java变量的初始化顺序:静态变量或静态语句块–>实例变量或初始化语句块–>构造方法–>@Autowired
使用构造方法注入,可以明确成员变量的加载顺序。

@Resource

当项目有多个相同类型的Bean被定义时,使用@Autowired会报错
@Resource的使用方式和@Autowired完全相同,最大的差异是@Resource支持ByName和ByType两种注入方式默认ByName匹配
如果使用name,Spring就根据bean的名字进行依赖注入,如果使用type,Spring就根据类型实现依赖注入。
如果两个属性都没配置,就先根据定义的属性名字去匹配,如果没匹配成功,再根据类型匹配。两个都没匹配到,就报错。

5.@Data

一般主要的功能是在实体类上面,主要功能是为了提供类的get、set、equals、hashCode、canEqual、toString方法,如果方法值默认不写是系统默认值
引用这个注解的时候还要加入依赖包才可导入,依赖包如下

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
</dependency>

只有结合这个依赖包工具库和注解@Data才可以进入自动注入。
例:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Books {
    private int bookID;
    private String bookName;
    private int bookCounts;
    private String detail;
}

@AllArgsConstructor : 注解在类上,有参构造
@NoArgsConstructor : 注解在类上,无参构造
自动生成代码如下:

package com.kk.pojo;

public class Books {
    private int bookID;
    private String bookName;
    private int bookCounts;
    private String detail;

    public int getBookID() {
        return this.bookID;
    }

    public String getBookName() {
        return this.bookName;
    }

    public int getBookCounts() {
        return this.bookCounts;
    }

    public String getDetail() {
        return this.detail;
    }

    public void setBookID(int bookID) {
        this.bookID = bookID;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public void setBookCounts(int bookCounts) {
        this.bookCounts = bookCounts;
    }

    public void setDetail(String detail) {
        this.detail = detail;
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof Books)) {
            return false;
        } else {
            Books other = (Books)o;
            if (!other.canEqual(this)) {
                return false;
            } else if (this.getBookID() != other.getBookID()) {
                return false;
            } else {
                label41: {
                    Object this$bookName = this.getBookName();
                    Object other$bookName = other.getBookName();
                    if (this$bookName == null) {
                        if (other$bookName == null) {
                            break label41;
                        }
                    } else if (this$bookName.equals(other$bookName)) {
                        break label41;
                    }

                    return false;
                }

                if (this.getBookCounts() != other.getBookCounts()) {
                    return false;
                } else {
                    Object this$detail = this.getDetail();
                    Object other$detail = other.getDetail();
                    if (this$detail == null) {
                        if (other$detail != null) {
                            return false;
                        }
                    } else if (!this$detail.equals(other$detail)) {
                        return false;
                    }

                    return true;
                }
            }
        }
    }

    protected boolean canEqual(Object other) {
        return other instanceof Books;
    }

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        int result = result * 59 + this.getBookID();
        Object $bookName = this.getBookName();
        result = result * 59 + ($bookName == null ? 43 : $bookName.hashCode());
        result = result * 59 + this.getBookCounts();
        Object $detail = this.getDetail();
        result = result * 59 + ($detail == null ? 43 : $detail.hashCode());
        return result;
    }

    public String toString() {
        return "Books(bookID=" + this.getBookID() + ", bookName=" + this.getBookName() + ", bookCounts=" + this.getBookCounts() + ", detail=" + this.getDetail() + ")";
    }

    public Books(int bookID, String bookName, int bookCounts, String detail) {
        this.bookID = bookID;
        this.bookName = bookName;
        this.bookCounts = bookCounts;
        this.detail = detail;
    }

    public Books() {
    }
}

6.@Path

@Path 注解可以标记在类名之上,也可以标记在方法名上。该注解接收一个value参数,表示定义资源的地址。
另外,资源地址相同,但是HTTP方法不同的两个方法是完全两个不同的REST接口,HTTP方法和资源地址相结合在一起才可以完成对一个资源的定位。

@Path就当@RequestMapping来用,如下:

	@Path("/clientWeb")
	public class  ClientWeb{       
		@GET        
		@Path("/getData")    
		public String getData(String params) {        
			return “xxx";    
			}`
	}

访问路径为:http://:/<应用域>/clientWeb/getData

7.@Configuration & @ConfigurationProperties @ @EnableConfigurationProperties

@Configuration

以前的原生spring,想要将组件添加到容器中:需要在resources目录下创建一个xml配置文件并创建bean标签
在这里插入图片描述
而注解@Configuration可以创建一个类,告诉Spring Boot这是一个配置类。
这时在类里不能写bean标签了,需要使用@bean注解给容器中添加组件,以方法名作为组件的id。返回类型为组件类型,返回的值,就是组件在容器中的实例。
在这里插入图片描述

@ConfigurationProperties

在Spring Boot中注解@ConfigurationProperties有三种使用场景,通常情况下使用的最多的只是其中的一种场景

  1. 场景一
    使用@ConfigurationProperties和@Component注解到bean定义类上,这里@Component代指同一类实例化Bean的注解。
// 将类定义为一个bean的注解,比如 @Component,@Service,@Controller,@Repository
// 或者 @Configuration
@Component
// 表示使用配置文件中前缀为user1的属性的值初始化该bean定义产生的的bean实例的同名属性
// 在使用时这个定义产生的bean时,其属性name会是Tom
@ConfigurationProperties(prefix = "user1")
public class User {
	private String name;
	// 省略getter/setter方法
}

对应application.properties配置文件内容如下:

user1.name=Tom

在此种场景下,当Bean被实例化时,@ConfigurationProperties会将对应前缀的后面的属性与Bean对象的属性匹配。符合条件则进行赋值。

  1. 场景二
    使用@ConfigurationProperties和@Bean注解在配置类的Bean定义方法上。以数据源配置为例:
@Configuration
public class DataSourceConfig {
 
	@Primary
	@Bean(name = "primaryDataSource")
	@ConfigurationProperties(prefix="spring.datasource.primary")
	public DataSource primaryDataSource() {
		return DataSourceBuilder.create().build();
	}
}

这里便是将前缀为“spring.datasource.primary”的属性,赋值给DataSource对应的属性值。

@Configuration注解的配置类中通过@Bean注解在某个方法上将方法返回的对象定义为一个Bean,并使用配置文件中相应的属性初始化该Bean的属性。

  1. 场景三
    使用@ConfigurationProperties注解到普通类,然后再通过@EnableConfigurationProperties定义为Bean。
@ConfigurationProperties(prefix = "user1")
public class User {
	private String name;
	// 省略getter/setter方法
}

这里User对象并没有使用@Component相关注解。
而该User类对应的使用形式如下:

@SpringBootApplication
@EnableConfigurationProperties({User.class})
public class Application {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }
}

上述代码中,通过@EnableConfigurationProperties对User进行实例化时,便会使用到@ConfigurationProperties的功能,对属性进行匹配赋值。

@EnableConfigurationProperties

@EnableConfigurationProperties的作用是把springboot配置文件中的值与我们的xxxProperties.java的属性进行绑定,需要配合@ConfigurationProperties使用。

不使用@EnableConfigurationProperties也能进行属性绑定,只需要给xxxProperties.java加上@Component注解,把它放到容器中,即可实现属性绑定。

8. @Inherited

@Inherited是一个标识,用来修饰注解
作用:如果一个类用上了@Inherited修饰的注解,那么其子类也会继承这个注解
注意:
1.接口用上个@Inherited修饰的注解,其实现类不会继承这个注解
2.父类的方法用了@Inherited修饰的注解,子类也不会继承这个注解
当用了@Inherited修饰的注解的@Retention是RetentionPolicy.RUNTIME,则增强了继承性,在反射中可以获取得到

9. @EnableScheduling & @Scheduled

@EnableScheduling 在配置类上使用,开启计划任务的支持(类上)
@Scheduled 来申明这是一个任务,包括cron,fixDelay,fixRate等类型(方法上,需先开启计划任务的支持)

配置类:

@Configuration
@ComponentScan("")
@EnableScheduling //通过@EnableScheduling注解开启对计划任务的支持
public class TaskScheduleConfig {
}

计划任务执行类:

@Service
public class ScheduledTaskService {
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
 
    @Scheduled(fixedRate = 5000) //通过@Scheduled声明该方法是计划任务,使用fixedRate属性每隔固定时间执行
    public void reportCurrentTime(){
        System.out.println("每隔5秒执行一次 "+dateFormat.format(new Date()));
    }
 
    @Scheduled(cron = "0 07 20 ? * *" ) //使用cron属性可按照指定时间执行,本例指的是每天20点07分执行;
    //cron是UNIX和类UNIX(Linux)系统下的定时任务
    public void fixTimeExecution(){
        System.out.println("在指定时间 "+dateFormat.format(new Date())+" 执行");
    }
}

运行类:

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TaskScheduleConfig.class);
    }
}

10. @EnableApolloConfig & @ApolloConfigChangeListener

@EnableApolloConfig

在这里插入图片描述

@ApolloConfigChangeListener

Apollo 本身是可以基于事件监听实时推送(Http长连接)变更(AutoUpdateConfigChangeListener),也会定时拉取(fallback)最新配置。
如果说我们还需要在配置更新时,做一些其他的业务,比如:对配置做了一些自己的数据缓存,或者业务变更等,那么我们需要控制监听器,apollo提供了这样的策略。可手动配置一个监听器在容器中。
用@ApolloConfigChangeListener注解标记,自动注册ConfigChangeListener

@Configuration
public class ApolloConfig {
 
    @Autowired
    private RefreshScope refreshScope;
 
    @ApolloConfigChangeListener(value = {"application", "datasource"})
    private void onChangeToAll(ConfigChangeEvent changeEvent) {
        ConfigChange change;
        for (String key : changeEvent.changedKeys()) {
            // 如果@ConfigurationProperties配置发生变化,则需要手动刷新
//            if (key.substring(0, 5).equals("nwpu")) {
//              refreshScope.refresh("nwpuDTO");
//            }
            change = changeEvent.getChange(key);
            // 打印出新增或者变化的配置 相关信息
            System.out.println(String.format("Change - key: %s, oldValue: %s, newValue: %s, changeType: %s",
                    change.getPropertyName(), change.getOldValue(), change.getNewValue(),
                    change.getChangeType()));
        }
    }
 
    @ApolloConfigChangeListener(value = "application", interestedKeyPrefixes = "nwpu")
    private void onChangeToApplication(ConfigChangeEvent changeEvent) {
        ConfigChange change;
        for (String key : changeEvent.changedKeys()) {
            // 如果@ConfigurationProperties配置发生变化,则需要手动刷新
            refreshScope.refresh("nwpuDTO");
            change = changeEvent.getChange(key);
            // 打印出新增或者变化的配置 相关信息
            System.out.println(String.format("Change - key: %s, oldValue: %s, newValue: %s, changeType: %s",
                    change.getPropertyName(), change.getOldValue(), change.getNewValue(),
                    change.getChangeType()));
        }
    }
 
}

11. @interface

注解@interface不是接口是注解类,在jdk1.5之后加入的功能,使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口。
在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。
如:spring中的@component注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {

	String value() default "";

}

@Target中的参数ElementType
该参数声明这个注解可以加在上面位置,只能在类上、或只能在方法上,具体如下:

public enum ElementType {
    TYPE,               /* 类、接口(包括注释类型)或枚举声明  */

    FIELD,              /* 字段声明(包括枚举常量)  */

    METHOD,             /* 方法声明  */

    PARAMETER,          /* 参数声明  */

    CONSTRUCTOR,        /* 构造方法声明  */

    LOCAL_VARIABLE,     /* 局部变量声明  */

    ANNOTATION_TYPE,    /* 注释类型声明  */

    PACKAGE             /* 包声明  */
}

@Retention中的参数RetentionPolicy

public enum RetentionPolicy {
    SOURCE,            /* Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了  */

    CLASS,             /* 编译器将Annotation存储于类对应的.class文件中。默认行为  */

    RUNTIME            /* 编译器将Annotation存储于class文件中,并且可由JVM读入 */
}

12.@PostConstruct

@PostConstruct是Java自带的注解,在方法上加该注解会在项目启动的时候执行该方法,也可理解为在spring容器初始化的时候执行该方法,,可作为一些数据的常规化加载,比如数据字典之类的。

从Java EE5规范开始,Servlet中增加了两个影响Servlet生命周期的注解,@PostConstruct和@PreDestroy,这两个注解被用来修饰一个非静态的void()方法。

其实从依赖注入的字面意思就可以知道,要将对象p注入到对象a,那么首先就必须得生成对象a和对象p,才能执行注入。所以,如果一个类A中有个成员变量p被@Autowried注解,那么@Autowired注入是发生在A的构造方法执行完之后的。如果想在生成对象时完成某些初始化操作,而偏偏这些初始化操作又依赖于依赖注入,那么久无法在构造函数中实现。为此,可以使用@PostConstruct注解一个方法来完成初始化,@PostConstruct注解的方法将会在依赖注入完成后被自动调用。Constructor >> @Autowired >> @PostConstruct

13. @Transactional

1.事务:

事务(Transactional) 就是把多个要做的操作组合成一个整体.利用事务的特性来保证操作的安全性,如果一个事务做到一半出现任何错误,就会进行回滚操作.来恢复成最初的模样.

2.事务的特性 (具有ACID的特性)

(1) A 原子性(atomicity) : 事务是一个不可分割的工作单位,事务中的操作要么都修改,要么都不修改。
(2) C 一致性(consistency):事务在完成时,必须是所有的数据都保持一致状态。
(3) I 隔离性(isolation):一个事务的执行不能被其他事务所影响。
(4) D 持久性(Durability): 持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的.

3. @Transactional

@Transactional 是java中使用的注解形式的事务,也就是说可以直接使用该注解来完成事务操作.
使用的位置: 该注解可以写在类或者方法上面.注意不能写在接口上!
方法的权限: 必须是public的方法才可以使用该注解.

默认情况下,事务遇到RuntimeException 时会回滚 . 遇到受检查的异常 是不会回滚的. 要想所有异常都回滚,要加上

@Transactional( rollbackFor={Exception.class,其它异常}) 

在这里插入图片描述

14. @ApiOperation

@ApiOperation不是spring自带的注解是swagger里的
com.wordnik.swagger.annotations.ApiOperation;

@ApiOperation和@ApiParam为添加的API相关注解,参数说明如下:

@ApiOperation(value = “接口说明”, httpMethod = “接口请求方式”, response = “接口返回参数类型”, notes = “接口发布说明”)
@ApiParam(required = “是否必须参数”, name = “参数名称”, value = “参数具体描述”)

实际项目中非常需要写文档,提高Java服务端和Web前端以及移动端的对接效率。
Swagger是当前最好用的Restful API文档生成的开源项目,通过swagger-spring项目实现了与SpingMVC框架的无缝集成功能,方便生成spring restful风格的接口文档,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值