提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
开发中我们可能要在spring项目中使用自定义注解来完成额外的业务模块,
该demo将展示如何适应AspectJ,用切面的方式,使用自定义注解
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</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-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.mabo</groupId>
<artifactId>JdbcTemplate</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>JdbcTemplate</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<xxl-job.version>2.3.0</xxl-job.version>
<rocketmq.version>4.9.3</rocketmq.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</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-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.8.0</version>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-common</artifactId>
<version>4.8.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>${xxl-job.version}</version>
</dependency>
<!-- <!– MQ Begin –>-->
<!-- <dependency>-->
<!-- <groupId>org.apache.rocketmq</groupId>-->
<!-- <artifactId>rocketmq-client</artifactId>-->
<!--<!– <version>${rocketmq.version}</version>–>-->
<!-- <version>4.9.3</version>-->
<!-- </dependency>-->
<!-- MQ End -->
</dependencies>
<!-- <build>-->
<!-- <plugins>-->
<!-- <plugin>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-maven-plugin</artifactId>-->
<!-- </plugin>-->
<!-- </plugins>-->
<!-- </build>-->
</project>
package com.mabo.controller;
import com.mabo.annotation.MyLog;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("myAnnotation")
public class MyAnnotationController {
@MyLog("日志测试1")
@RequestMapping("test1")
public String test1(@RequestParam("id")String id) {
System.out.println("这是原本的方法test1,id:"+id);
return "成功";
}
@MyLog("日志测试2")
@RequestMapping("test2")
public void test2() {
System.out.println("这是原本的方法test2");
}
}
package com.mabo.annotation;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyLog {
String value() default "";
}
package com.mabo.annotation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* @Description : 定义自定义注解的切面
* @Author : mabo
*/
@Component
@Aspect
public class MyLogAspect {
@Pointcut("@annotation(com.mabo.annotation.MyLog)")
private void pointcut(){}
@Before("@annotation(logger)")
public void before(JoinPoint joinPoint, MyLog logger) {
Signature signature = joinPoint.getSignature();
Class aClass = signature.getDeclaringType();
System.out.println("Before执行的方法:"+aClass.getName()+"."+signature.getName());
System.out.println("注解的值为:"+logger.value());
}
//ProceedingJoinPoint只能用在around注解
/**
* @Description : 使用Around可以修改方法的参数,返回值,
* 甚至不执行原来的方法,但是原来的方法不执行会导致before和after注解的内容不执行
*/
@Around("@annotation(logger)")
public Object around(ProceedingJoinPoint joinPoint, MyLog logger) throws Throwable {
Object[] objects = {"1123"};
System.out.println("around方法执行前");
//执行原方法,可以注掉不执行
Object proceed = joinPoint.proceed(objects);
//不执行原方法
System.out.println("around方法已经执行");
return "返回结果修改测试"+proceed.toString();
// return "返回结果修改测试";
}
@After("@annotation(logger)")
public void after(JoinPoint joinPoint, MyLog logger) {
Signature signature = joinPoint.getSignature();
Class aClass = signature.getDeclaringType();
System.out.println("after执行的方法:"+aClass.getName()+"."+signature.getName());
System.out.println("注解的值为:"+logger.value());
}
}
JAVA 基础知识点
什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”?
Java虚拟机是一个可以执行Java字节码的虚拟机进程。Java源文件被编译成能被Java虚拟机执行的字节码文件。
Java被设计成允许应用程序可以运行在任意的平台,而不需要程序员为每一个平台单独重写或者是重新编译。Java虚拟机让这个变成可能,因为它知道底层硬件平台的指令长度和其它特性。
什么是J2EE?JVM?JRE?JDK?
(1)J2EE:是为开发企业环境下的应用程序提供的一套解决方案,该技术体系中包含的技术如Servlet、Jsp等,主要针对Web应用程序开发。
(2)JVM:JVM是java虚拟机(JVM Java Virtual Machine),java程序需要运行在虚拟机上,不同平台有自己的虚拟机,因此java语言可以跨平台。
(3)JRE:包括Java虚拟机(JVM Java Virtual Machine)和Java程序所需的核心类库等如果想要运行一个开发好的Java程序,计算机中只需要安装JRE即可。JRE:JVM+类库。
(4)JDK:JDK是提供给Java开发人员使用的,其中包含了java的开发工具,也包括了JRE。所以安装了JDK,就不用在单独安装JRE了。其中的开发工具:编译工具(javac.exe) 打包工具(jar.exe)等。JDK:JRE+JAVA的开发工具。
static关键字是什么意思?Java中是否可以覆盖(override)一个private或者是static方法?
“static”关键字表明一个成员变量或者是成员方法可以在没有所属的类的实例变量的情况下被访问。
Java中static方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而static方法是编译时静态绑定的。static方法跟类的任何实例都不相关,所以概念上不适用。
Java中也不可以覆盖private方法,因为private修饰的变量和方法只能在当前类中使用,如果是其它类继承当前类,是不能访问到private变量或方法的,当然也不能覆盖。
是否可以在static环境中访问非static变量?
static变量在Java中是属于类的,它在所有的实例中的值是一样的,当类被Java虚拟机载入的时候,会对static变量进行初始化。如果你的代码尝试不用实例来访问非static的变量,编译器会报错,因为这些变量还没有被创建出来,还没有跟任何实例关联上。
Java支持的数据类型有哪些?什么是自动拆装箱?
Java语言支持的8种基本数据类型是:
boolean
byte、char
short、int
long、float、double
自动装箱是Java编译器在基本数据类型和对应的对象包装类型之间做的一个转化。比如:把int转化成integer,double转化成Double,等等。反之就是自动拆箱。
面向对象的三大特性(继承、封装、多态)
继承、封装、多态
什么是继承?
①继承是面向对象程序设计能够提高软件开发效率的重要原因之一。
②继承是具有传递性的,就像现实中孙子不仅长得像爸爸而且还像他爷爷。
③继承来的属性和方法是隐式的,也就是在本类里面是看不见的。
④一个类只能有一个父类,也就是类只能是单继承。
⑤一个接口可以有多个父类,也就是接口可以是多继承。
实际项目开发中,一个类继承于另一个类,那么前者就是后者的子类,反则反之。
什么是封装?
对象数据和操作该对象的指令都是对象自身的一部分,能够实现尽可能对外部隐藏数据。
实际项目开发中,使用封装最多的就是实体类,常常和JavaBean(类必须是具体的和公共的,并且具有无参数的构造器)一起使用。
那么,实体类有那些东西呢?
答:私有的成员变量、无参数的构造器、有参数的构造器、setter和getters方法、重写tostring方法、重写hashCode和equals方法。
什么是多态?
①多态就是对象拥有多种形态:引用多态和方法多态。
②引用多态:父类的引用可以指向本类对象、父类的引用可以指向子类的对象。
③方法多态:创建本类对象时,调用的方法为本类的方法;创建子类对象时,调用的方法为子类重写的方法或者继承的方法。
④存在多态的必要条件:继承、重写。
⑤多态的作用是消除类型之间的耦合关系。
在实际项目开发中,A类继承B类,如果在A类中不重写B类的方法的时候,输出的仍旧是B类方法里面的信息(B b=new A());如果在A类中重写B类的方法的时候,输出的是A类方法里面的信息(B b=new A())。
java为什么不支持多继承?
1.若子类继承的父类中拥有相同的成员变量,子类在引用该变量时将无法判别使用哪个父类的成员变量。
2.若一个子类继承的多个父类拥有相同方法,同时子类并未覆盖该方法(若覆盖,则直接使用子类中该方法),那么调用该方法时将无法确定调用哪个父类的方法。
Java 中覆盖和重载是什么意思?
解析:覆盖和重载是比较重要的基础知识点,并且容易混淆,所以面试中常见。
答:覆盖(Overide)是指子类对父类方法的一种重写,只能比父类抛出更少的异常,访问权限不能比父类的小。
被覆盖的方法不能是 private 的,否则只是在子类中重新定义了一个方法;
重载(Overload)表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同。
面试官: 那么构成重载的条件有哪些?
答:参数类型不同、参数个数不同、参数顺序不同。
面试官: 函数的返回值不同可以构成重载吗?为什么?
答:不可以,因为 Java 中调用函数并不需要强制赋值。举例如下:
如下两个方法:
void f(){}
int f(){ return 1;}
1
2
只要编译器可以根据语境明确判断出语义,比如在 int x = f();中,那么的确可以据此区分重载方法。不过, 有时你并不关心方法的返回值,你想要的是方法调用的其他效果 (这常被称为 “为了副作用而调用”),这时你可能会调用方法而忽略其返回值,所以如果像下面的调用:
fun();
此时 Java 如何才能判断调用的是哪一个 f() 呢?别人如何理解这种代码呢?所以,根据方法返回值来区分重载方法是行不通的。
重定向和转发的区别。
1、重定向是两次请求,转发是一次请求,因此转发的速度要快于重定向
2、重定向之后地址栏上的地址会发生变化,变化成第二次请求的地址,转发之后地址栏上的地址不会变化,还是第一次请求的地址
3、转发是服务器行为,重定向是客户端行为。重定向时浏览器上的网址改变 ,转发是浏览器上的网址不变
4、重定向是两次request,转发只有一次请求
5、重定向时的网址可以是任何网址,转发的网址必须是本站点的网址
抽象类和接口的区别有哪些?
答:
抽象类中可以没有抽象方法;接口中的方法必须是抽象方法;
抽象类中可以有普通的成员变量;接口中的变量必须是 static final 类型的,必须被初始化 , 接口中只有常量,没有变量。
抽象类只能单继承,接口可以继承多个父接口;
Java8 中接口中会有 default 方法,即方法可以被实现。
面试官:抽象类和接口如何选择?
答:
如果要创建不带任何方法定义和成员变量的基类,那么就应该选择接口而不是抽象类。
如果知道某个类应该是基类,那么第一个选择的应该是让它成为一个接口,只有在必须要有方法定义和成员变量的时候,才应该选择抽象类。因为抽象类中允许存在一个或多个被具体实现的方法,只要方法没有被全部实现该类就仍是抽象类。