2021-02-19实习日报

1. Java自定义注解

1.1注解定义

注解通过@interface关键字进行定义

public @interface TestAnnotation{
}

创建一个名称为TestAnnotation的注解,形式和接口类似,多了个@符号

1.2 注解的应用
@TestAAnnotation
public class Test{
}

创建一个类Test,然后在类定义的地方加上@TestAnnotation
注解的使用还需要搭配上元注解

1.3 元注解

元注解:是一种基本注解,可以应用到其他注解上面
元注解标签有:@Retention,@Documented,@Target,@Inherited,@Repeatable

1.3.1 @Retention

Retention的英文时候保留期,注解的作用是说明这个注解的存活时间
属性如下

注解名称注解作用
RetentionPolicy.SOURCE注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视
RetentionPolicy.CLASS注解只被保留到编译进行的时候,它并不会被加载到 JVM 中
RetentionPolicy.RUNTIME注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们

使用方法

@Retention(RententionPolicy.RUNTIME)
public @inteface TestAnnotation{
}

指定了注解TestAnnotation注解的存活时间为RUNTIME,可以在程序运行周期被获取到

1.3.2 @Documented

它的作用是将注解中的元素包含到Javadoc中
没有什么具体的属性

1.3.3 @Target

@Target指定了注解运用的地方,当一个注解被@Target注解时,这个注解就被限定了运用的场景
属性如下

注解名称注解作用
ElementType.ANNOTATION_TYPE可以给一个注解进行注解
ElementType.CONSTRUCTOR可以给构造方法进行注解
ElementType.FIELD可以给属性进行注解
ElementType.LOCAL_VARIABLE可以给局部变量进行注解
ElementType.METHOD可以给方法进行注解
ElementType.PACKAGE可以给一个包进行注解
ElementType.PARAMETER可以给一个方法内的参数进行注解
ElementType.TYPE可以给一个类型进行注解,比如类、接口、枚举
1.3.4 @Inherited

Inherited是继承的意思,但是并不是说注解本身可以继承而是说如果一个超类被@Inherited注解过的注解进行注解的话,那么如果他的子类没有被任何注解应用的话,那么这个子类继承了超类的注解
使用方法

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test{}

@Test
public class{}

public class B extends A{}

注解Test被@Inherited修饰,之后类A被Test注解,类B继承A,类B也拥有Test注解

1.3.5 @Repeatable

Repeatable是可重复的意思,表示这个注解可以多次运用,通常是注解的值可以同时取多个
使用方法

@interface Persons {
    Person[]  value();
}

@Repeatable(Persons.class)
@interface Person{
    String role default "";
}

@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan{

}

@Repeatable注解了Person,而@Repeateable后面的括号中的类相当于一个容器注解
容器注解:用来存放其他注解的地方,本身也是注解
代码中的容器注解

@interface Persons {
    Person[]  value();
}

按照规定,定义中必须有一个value的属性,属性类型是被@Repeatable注解过的注解数组

如果不好理解的话,可以这样理解。Persons 是一张总的标签,上面贴满了 Person 这种同类型但内容不一样的标签。把 Persons 给一个 SuperMan 贴上,相当于同时给他贴了程序员、产品经理、画家的标签。

代码中的@Person(role=“artist”)还涉及到了注解的属性

1.4 注解的属性

注解的属性也叫做成员变量,注解只有成员变量,没有方法,注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {

    int id();

    String msg();

}

代码中i定义了TestAnnotation这个注解中拥有id和msg两个属性,使用时需要给他们赋值
赋值的方式是在注解的括号内以 value=”” 形式,多个属性之前用 ,隔开

@TestAnnotation(id=3,msg="hello annotation")
public class Test {

}

在注解中定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解及它们的数组。

注解中属性可以有默认值,默认值需要用 default 关键值指定

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {

    public int id() default -1;

    public String msg() default "Hi";

}

TestAnnotation中id属性默认值为-1,msg属性默认值为Hi

@TestAnnotation()
public class Test {}

因为有默认值,所以无需要再在 @TestAnnotation 后面的括号里面进行赋值了,这一步可以省略。

另外,还有一种情况。如果一个注解内仅仅只有一个名字为 value 的属性时,应用这个注解时可以直接接属性值填写到括号内。

public @interface Check {
    String value();
}
@Check("hi")
int a;
//两个效果相同
@Check(value="hi")
int a;

还需要注意一种情况是一个注解没有任何属性

public @interface Perform {}

应用时连括号都可以省略

@Perform
public void testMethod(){}
1.5 java预置的注解
1.5.1 @Deprecated

这个元素是用来标记过时的元素,编译器在编译阶段遇到这个注解时会发出提醒警告,告诉开发者正在调用一个过时的元素比如过时的方法、过时的类、过时的成员变量。

public class Hero {

    @Deprecated
    public void say(){
        System.out.println("Noting has to say!");
    }


    public void speak(){
        System.out.println("I have a dream!");
    }


}

调用say() 方法的话会被一条直线划了,这其实就是编译器识别后的提醒效果。

1.5.2 @Override

提示子类要复写父类中被 @Override 修饰的方法

1.5.3 @SuppressWarnings

阻止警告的意思。之前说过调用被 @Deprecated 注解的方法后,编译器会警告提醒,而有时候开发者会忽略这种警告,他们可以在调用的地方通过 @SuppressWarnings 达到目的。

@SuppressWarnings("deprecation")
public void test1(){
    Hero hero = new Hero();
    hero.say();
    hero.speak();
}
1.5.4 @SafeVarargs

参数安全类型注解。它的目的是提醒开发者不要用参数做一些不安全的操作,它的存在会阻止编译器产生 unchecked 这样的警告。它是在 Java 1.7 的版本中加入的。

@SafeVarargs // Not actually safe!
    static void m(List<String>... stringLists) {
    Object[] array = stringLists;
    List<Integer> tmpList = Arrays.asList(42);
    array[0] = tmpList; // Semantically invalid, but compiles without warnings
    String s = stringLists[0].get(0); // Oh no, ClassCastException at runtime!
}
1.5.5 @FunctionalInterface

函数式接口注解,这个是 Java 1.8 版本引入的新特性。函数式编程很火,所以 Java 8 也及时添加了这个特性。

函数式接口 (Functional Interface) 就是一个具有一个方法的普通接口。

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

2. Spring中的ApplicationListener

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener{}

ApplicationListener<>里边的泛型需要继承ApplicationEvent的抽象方法

项目中的使用

public class HandleInit implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        Map<String,Object> beans = event.getApplicationContext().getBeansWithAnnotation(MsgType.class);
        for(Object bean : beans.values()){
            MsgType msgType = bean.getClass().getAnnotation(MsgType.class);
            HandleFactory.registerHandleService(msgType.value(),(HandleService) bean);
        }
    }
}

contextRefreshedEvent为上下文刷新事件,实现了这个接口,Spring容器加载完毕后,就会执行这个实现类重写的方法

这样,当ioc容器加载处理完相应的bean之后,也给我们提供了一个机会(先有InitializingBean,后有ApplicationListener),可以去做一些自己想做的事。其实这也就是spring ioc容器给提供的一个扩展的地方。我们可以这样使用这个扩
展机制,首先需要认识几个相关的接口
org.springframework.context.ApplicationEvent
org.springframework.context.ApplicationListener
一个最简单的方式就是,让我们的bean实现ApplicationListener接口,这样当发布事件时,spring的ioc容器就会以容器的实例对象作为事件源类,并从中找到事件的监听者,此时
ApplicationListener接口实例中的onApplicationEvent(E event)方法就会被调用,我们的逻辑代码就会写在此处。这样我们的目的就达到了。但这也带来一个思考,有人可能会
想,这样的代码我们也可以通过实现spring的InitializingBean接口来实现啊,也会被spring容器去自动调用,但是大家应该想到,如果我们现在想做的事,是必须要等到所有的
bean都被处理完成之后再进行,此时InitializingBean接口的实现就不合适了,所以需要深刻理解事件机制的应用场合。

3. redis发布订阅

3.1 需要的依赖
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
3.2 配置redis以及连接池
# redis
spring:
  redis:
    host: 127.0.0.1
    port: 6379
#    password:
    database: 1
    timeout: 5000
    jedis:
      pool:
        max-active: 8
        max-wait: 1
        max-idle: 500
        min-idle: 0
3.3 创建消息的发布者和消息处理者类

消息发布者

@EnableScheduling//开启定时器功能
@Component
public class MessageSender {
  @Autowired
  private StringRedisTemplate stringRedisTemplate;

  /**
   * 间隔2秒,通过stringRedisTemplate对象向redis消息队列chat频道发布消息
   */
  @Scheduled(fixedDelay = 2000)
  public void sendMessage() {
    stringRedisTemplate.convertAndSend("chat", String.valueOf(Math.random()));
  }
}

消息处理器pojo

@Component
public class MessageReceiver {

  /**
   * 接收消息方法
   */
  public void receiverMessage(String message) {
    System.out.println("MessageReceiver收到一条新消息:" + message);
  }
}
3.4 设置消息发布者,消息处理者POJO,redis消息监听容器以及redis监听器注入IOC容器
/**
 * redis配置
 *
 * @author 段誉
 * @create 2019-03-25 9:59
 */
@Configuration//相当于xml中的beans
public class RedisConfig {

  @Bean
  RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
                                          MessageListenerAdapter listenerAdapter) {
    RedisMessageListenerContainer container = new RedisMessageListenerContainer();
    container.setConnectionFactory(connectionFactory);
    //订阅了一个叫chat的通道
    container.addMessageListener(listenerAdapter, new PatternTopic("chat"));
    return container;
  }

  /**
   * 消息监听器适配器,绑定消息处理器,利用反射技术调用消息处理器的业务方法
   * @param receiver
   * @return
   */
  @Bean
  MessageListenerAdapter listenerAdapter(MessageReceiver receiver) {
    //给messageListenerAdapter 传入一个消息接受的处理器,利用反射的方法调用“receiveMessage”
    //不填defaultListenerMethod默认调用handleMessage
    return new MessageListenerAdapter(receiver, "receiverMessage");
  }

  /**
   * 读取内容的template
   */
  @Bean
  StringRedisTemplate template(RedisConnectionFactory connectionFactory) {
    return new StringRedisTemplate(connectionFactory);
  }
}

4. Prometheus+Grafana监控

4.1 依赖内容

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>io.micrometer</groupId>
			<artifactId>micrometer-registry-prometheus</artifactId>
			<version>1.1.3</version>
		</dependency>
	</dependencies>
4.2 配置文件

配置文件中加入配置,这里就只进行一些简单配置,management.metrics.tags.application属性是本文配合Grafana的Dashboard设置的

spring.application.name=springboot_prometheus
management.endpoints.web.exposure.include=*
management.metrics.tags.application=${spring.application.name}
4.3设置application

修改启动类

@SpringBootApplication
public class Springboot2PrometheusApplication {

	public static void main(String[] args) {
		SpringApplication.run(Springboot2PrometheusApplication.class, args);
	}
	@Bean
	MeterRegistryCustomizer<MeterRegistry> configurer(
			@Value("${spring.application.name}") String applicationName) {
		return (registry) -> registry.config().commonTags("application", applicationName);
	}
}

访问http://localhost:8080/actuator/prometheus

4.4 Prometheus配置
# my global config
global:
  scrape_interval:     15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
  alertmanagers:
  - static_configs:
    - targets:
      # - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - "first_rules.yml"
  # - "second_rules.yml"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  - job_name: 'prometheus'
    static_configs:
    - targets: ['127.0.0.1:9090']
###以下内容为SpringBoot应用配置
  - job_name: 'springboot_prometheus'
    scrape_interval: 5s
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['127.0.0.1:8080']
4.5 启动Prometheus

在这里插入图片描述

查看Prometheus监控的应用
target按钮
在这里插入图片描述

列表中UP的页面为存活的实例
在这里插入图片描述

也可以查看很多指数
在这里插入图片描述

4.6 Grafana配置

从官网上下载并启动
sudo service grafana-server start
启动服务 访问http://localhost:3000
在这里插入图片描述
添加数据源
在这里插入图片描述

4.7 Grafana图表大概参数解析

首先添加一个图表
在这里插入图片描述

这里变量应该监控项可以使用/.*/以表示应用集所有的变量,Grafana还可以使用正则来表示某些参数,比如test[\s]或test[^0,1,2].*等等,这些可以根据需求来做一些相应的调整

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值