当前位置: 首页 > news >正文

池州集团网站建设/甘肃新站优化

池州集团网站建设,甘肃新站优化,做fcr的网站,行政单位门户网站建设规定代理模式 package org.example.proxy;public class ProxyClient {public static void main(String[] args) {ProxyBuilder proxyBuilder new ProxyBuilder();proxyBuilder.build();} }interface BuildDream {void build(); }class CustomBuilder implements BuildDream {Over…

代理模式

package org.example.proxy;public class ProxyClient {public static void main(String[] args) {ProxyBuilder proxyBuilder = new ProxyBuilder();proxyBuilder.build();}
}interface BuildDream {void build();
}class CustomBuilder implements BuildDream {@Overridepublic void build() {System.out.println("自定义执行方法");}
}class ProxyBuilder implements BuildDream {private CustomBuilder customBuilder;@Overridepublic void build() {if (this.customBuilder == null) {this.customBuilder = new CustomBuilder();}System.out.println("代理执行前");customBuilder.build();System.out.println("代理执行后");}
}

执行结果:

代理执行前
自定义执行方法
代理执行后

动态代理

Java 动态代理是一种设计模式,允许在运行时创建代理对象,以拦截对目标对象的方法调用。动态代理通常用于横切关注点(如日志记录、事务管理、权限控制等)的实现。Java 提供了两种主要的动态代理机制:

  1. JDK 动态代理:基于接口的代理。
  2. CGLIB 动态代理:基于类的代理。

JDK 动态代理

JDK 动态代理使用 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口来实现。它只能代理实现了接口的类。

示例代码
package org.example.proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** JDK动态代理实现*/
public class DynamicProxy {public static void main(String[] args) {MyService myService = (MyService) MyServiceProxy.newProxyInstance(new MyServiceImpl());myService.saveInfo();}
}// 定义接口
interface MyService {void saveInfo();
}// 实现接口的类
class MyServiceImpl implements MyService {@Overridepublic void saveInfo() {System.out.println("保存信息成功");}
}class MyServiceProxy implements InvocationHandler {private Object target;MyServiceProxy(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("代理方法执行前");Object result = method.invoke(target, args);System.out.println("代理方法执行后");return result;}public static Object newProxyInstance(Object target) {return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new MyServiceProxy(target));}
}

执行结果:

代理方法执行前
保存信息成功
代理方法执行后

CGLIB 动态代理

CGLIB 动态代理使用字节码生成库来生成代理类,它可以代理没有实现接口的类。

示例代码
package org.example.proxy;import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** CGLIB实现动态代理*/
public class CGLibProxy {public static void main(String[] args) {HerService herService = (HerService) ProxyServiceInterceptor.newProxyInstance(new HerService());herService.saveInfo();herService.sayHello();}
}class HerService {public void saveInfo() {System.out.println("保存信息成功");}public void sayHello() {System.out.println("Hi");}
}class ProxyServiceInterceptor implements MethodInterceptor {private Object target;ProxyServiceInterceptor(Object target) {this.target = target;}@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("代理方法执行前");Object result = methodProxy.invokeSuper(o, objects);System.out.println("代理方法执行后");return result;}public static Object newProxyInstance(Object target) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(target.getClass());enhancer.setCallback(new ProxyServiceInterceptor(target));return enhancer.create();}
}

运行结果:

代理方法执行前
保存信息成功
代理方法执行后
代理方法执行前
Hi
代理方法执行后

总结

  • JDK 动态代理:适用于代理实现了接口的类。
  • CGLIB 动态代理:适用于代理没有实现接口的类。

这两种动态代理机制都可以用于实现 AOP(面向切面编程),以便在不修改目标对象代码的情况下添加额外的功能。

AOP

AOP(面向切面编程)是一种编程范式,它允许你在不修改业务逻辑代码的情况下,添加横切关注点(如日志记录、事务管理、权限控制等)。Spring Framework 提供了强大的 AOP 支持,主要通过以下几种方式实现:

  1. 基于代理的 AOP:使用 JDK 动态代理或 CGLIB 动态代理。
  2. 基于注解的 AOP:使用注解来定义切面和切点。
  3. 基于 XML 配置的 AOP:使用 XML 配置文件来定义切面和切点。

基于注解的 AOP 示例

下面是一个使用 Spring AOP 和注解的示例,展示了如何在 Spring 应用程序中使用 AOP。

1. 添加依赖

首先,确保你的项目中包含 Spring AOP 相关的依赖。如果你使用的是 Maven,可以在 pom.xml 中添加以下依赖:

<dependencies><!-- Spring AOP --><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.3.10</version></dependency><!-- AspectJ --><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.3.10</version></dependency>
</dependencies>
2. 定义业务逻辑类

定义一个简单的业务逻辑类:

package com.example.service;import org.springframework.stereotype.Service;@Service
public class HelloService {public void sayHello() {System.out.println("Hello, World!");}
}
3. 定义切面类

定义一个切面类,使用注解来指定切点和通知:

package com.example.aspect;import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;@Aspect
@Component
public class LoggingAspect {@Before("execution(* com.example.service.HelloService.sayHello(..))")public void logBefore() {System.out.println("Before method call");}@After("execution(* com.example.service.HelloService.sayHello(..))")public void logAfter() {System.out.println("After method call");}
}
4. 配置 Spring 应用程序

创建一个 Spring 配置类,启用 AOP 支持:

package com.example.config;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;@Configuration
@ComponentScan(basePackages = "com.example")
@EnableAspectJAutoProxy
public class AppConfig {
}
5. 测试代码

编写一个测试类来验证 AOP 的效果:

package com.example;import com.example.config.AppConfig;
import com.example.service.HelloService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class Main {public static void main(String[] args) {ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);HelloService helloService = context.getBean(HelloService.class);helloService.sayHello();}
}

运行结果

当你运行测试代码时,输出将会是:

Before method call
Hello, World!
After method call

解释

  1. 业务逻辑类HelloService 是一个简单的业务逻辑类,包含一个 sayHello 方法。
  2. 切面类LoggingAspect 是一个切面类,包含两个通知方法 logBeforelogAfter,分别在 sayHello 方法调用之前和之后执行。
  3. Spring 配置类AppConfig 是一个 Spring 配置类,启用了 AOP 支持并扫描指定包中的组件。
  4. 测试代码:在测试代码中,通过 Spring 容器获取 HelloService 的代理对象,并调用 sayHello 方法。

总结

通过使用 Spring AOP 和注解,你可以在不修改业务逻辑代码的情况下,轻松地添加横切关注点。Spring AOP 提供了强大的功能和灵活性,使得代码更加模块化和可维护。

@Before中的参数

在 Spring AOP 中,@Before 注解用于定义一个前置通知(Advice),它会在目标方法执行之前执行。@Before 注解的参数是一个切点表达式,用于指定哪些方法应该被拦截。切点表达式可以使用多种方式来匹配目标方法,包括方法签名、注解、包名等。

常见的切点表达式

  1. 匹配方法签名

    • execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
    • 例如:execution(* com.example.service.HelloService.sayHello(..))
  2. 匹配类上的注解

    • @within(annotationType)
    • 例如:@within(org.springframework.stereotype.Service)
  3. 匹配方法上的注解

    • @annotation(annotationType)
    • 例如:@annotation(org.springframework.transaction.annotation.Transactional)
  4. 匹配包名

    • within(package-name)
    • 例如:within(com.example.service..*)
  5. 匹配参数

    • args(argument-types)
    • 例如:args(String, ..)

示例代码

以下是一些常见的 @Before 注解的使用示例:

1. 匹配特定方法

匹配 com.example.service.HelloService 类中的 sayHello 方法:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;@Aspect
@Component
public class LoggingAspect {@Before("execution(* com.example.service.HelloService.sayHello(..))")public void logBefore() {System.out.println("Before method call");}
}
2. 匹配特定包中的所有方法

匹配 com.example.service 包及其子包中的所有方法:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;@Aspect
@Component
public class LoggingAspect {@Before("within(com.example.service..*)")public void logBefore() {System.out.println("Before method call");}
}
3. 匹配带有特定注解的方法

匹配带有 @Transactional 注解的方法:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;@Aspect
@Component
public class LoggingAspect {@Before("@annotation(org.springframework.transaction.annotation.Transactional)")public void logBefore() {System.out.println("Before transactional method call");}
}
4. 匹配带有特定参数的方法

匹配第一个参数为 String 类型的方法:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;@Aspect
@Component
public class LoggingAspect {@Before("args(java.lang.String, ..)")public void logBefore() {System.out.println("Before method call with String argument");}
}

组合切点表达式

你可以使用 &&||! 运算符来组合多个切点表达式。例如,匹配 com.example.service 包中的所有方法,并且这些方法带有 @Transactional 注解:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;@Aspect
@Component
public class LoggingAspect {@Before("within(com.example.service..*) && @annotation(org.springframework.transaction.annotation.Transactional)")public void logBefore() {System.out.println("Before transactional method call in service package");}
}

总结

  • 匹配特定方法:使用 execution 表达式。
  • 匹配特定包中的所有方法:使用 within 表达式。
  • 匹配带有特定注解的方法:使用 @annotation 表达式。
  • 匹配带有特定参数的方法:使用 args 表达式。
  • 组合切点表达式:使用 &&||! 运算符。

通过合理使用这些切点表达式,你可以灵活地定义哪些方法应该被拦截,从而实现各种横切关注点的功能。

反射

package org.example.reflect;import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class ReflectTest {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {Class<?> aClass = Class.forName("org.example.reflect.Student");Class<Student> studentClass = Student.class;Constructor<Student> constructor = studentClass.getDeclaredConstructor(String.class, Integer.class);constructor.setAccessible(true);Student oh = constructor.newInstance("Oh", 66);//        Constructor<?>[] constructors = aClass.getDeclaredConstructors();
//        Iterator<Constructor<?>> constructorIterator = Arrays.stream(constructors).iterator();
//        while (constructorIterator.hasNext()) {
//            System.out.println(constructorIterator.next());
//        }Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(String.class, Integer.class);// 为私有构造函数获取访问性declaredConstructor.setAccessible(true);Student instance = (Student) declaredConstructor.newInstance("Xin", 25);
//        instance.printInfo();Method declaredMethod = aClass.getDeclaredMethod("printInfo");declaredMethod.setAccessible(true);String result = (String) declaredMethod.invoke(instance);System.out.println(result);System.out.println(declaredMethod.invoke(oh).toString());}
}class Student {private String name;private Integer age;public Student() {System.out.println("无参构造函数");}private Student(String name, Integer age) {this.name = name;this.age = age;}private String printInfo() {System.out.println(this.name + " " + this.age);return "OK";}
}

Annotation

实现自定义注解

在Java中,自定义注解和使用AOP(面向切面编程)来扫描带有该注解的类和方法,可以通过以下步骤实现。我们将使用Spring AOP来实现这一功能。

1. 创建自定义注解

首先,我们需要创建一个自定义注解。例如,我们创建一个名为 @MyAnnotation 的注解:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface MyAnnotation {String value() default "";
}

2. 创建AOP切面

接下来,我们需要创建一个AOP切面类,用于拦截带有 @MyAnnotation 注解的方法或类。我们可以使用Spring AOP来实现这一点。

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;@Aspect
@Component
public class MyAnnotationAspect {@Before("@within(myAnnotation) || @annotation(myAnnotation)")public void beforeMethod(MyAnnotation myAnnotation) {// 在方法执行之前执行的逻辑System.out.println("Intercepted method with annotation: " + myAnnotation.value());}
}

3. 配置Spring AOP

为了使AOP切面生效,我们需要在Spring配置文件中启用AOP支持。可以在Spring Boot应用程序的主类中添加 @EnableAspectJAutoProxy 注解:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;@SpringBootApplication
@EnableAspectJAutoProxy
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}
}

4. 使用自定义注解

现在,我们可以在类或方法上使用自定义注解 @MyAnnotation,并且AOP切面会拦截这些带有注解的方法或类。

import org.springframework.stereotype.Service;@Service
public class MyService {@MyAnnotation(value = "testMethod")public void testMethod() {System.out.println("Executing testMethod");}
}

5. 运行应用程序

启动Spring Boot应用程序,并调用带有 @MyAnnotation 注解的方法。你会看到AOP切面拦截了该方法,并执行了 beforeMethod 中的逻辑。

总结

通过上述步骤,我们实现了自定义注解,并使用Spring AOP扫描带有该注解的类和方法,从而实现类似于Spring的操作。关键步骤包括创建自定义注解、创建AOP切面类、配置Spring AOP以及在类或方法上使用自定义注解。

@Retention@Target 注解

@Retention@Target 是Java注解的元注解(meta-annotations),它们用于定义自定义注解的行为和适用范围。

@Retention

@Retention 注解指定了自定义注解的保留策略,即注解在什么阶段仍然存在。RetentionPolicy 枚举有以下几种值:

  • RetentionPolicy.SOURCE:注解只在源代码中存在,编译器在编译时会丢弃这种注解。
  • RetentionPolicy.CLASS:注解在编译时被保留在类文件中,但在运行时不会被JVM保留。这是默认的保留策略。
  • RetentionPolicy.RUNTIME:注解在运行时也会被JVM保留,因此可以通过反射机制读取这种注解。

在你的例子中,@Retention(RetentionPolicy.RUNTIME) 表示 @MyAnnotation 注解在运行时也会被保留,因此可以通过反射机制读取。

@Target

@Target 注解指定了自定义注解可以应用的Java元素类型。ElementType 枚举有以下几种值:

  • ElementType.TYPE:可以应用于类、接口(包括注解类型)或枚举声明。
  • ElementType.FIELD:可以应用于字段或属性。
  • ElementType.METHOD:可以应用于方法。
  • ElementType.PARAMETER:可以应用于方法参数。
  • ElementType.CONSTRUCTOR:可以应用于构造函数。
  • ElementType.LOCAL_VARIABLE:可以应用于局部变量。
  • ElementType.ANNOTATION_TYPE:可以应用于注解类型。
  • ElementType.PACKAGE:可以应用于包声明。
  • ElementType.TYPE_PARAMETER:可以应用于类型参数(Java 8及以上)。
  • ElementType.TYPE_USE:可以应用于任何使用类型的地方(Java 8及以上)。

在你的例子中,@Target({ElementType.METHOD, ElementType.TYPE}) 表示 @MyAnnotation 注解可以应用于方法和类(包括接口和枚举)。

总结

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface MyAnnotation {String value() default "";
}
  • @Retention(RetentionPolicy.RUNTIME):表示 @MyAnnotation 注解在运行时也会被保留,可以通过反射机制读取。
  • @Target({ElementType.METHOD, ElementType.TYPE}):表示 @MyAnnotation 注解可以应用于方法和类(包括接口和枚举)。

通过这些元注解的配置,你可以控制自定义注解的行为和适用范围。

重新理解@Transactional

@Transactional 是 Spring 提供的一个非常重要的注解,用于声明式事务管理。它可以应用于类或方法上,以便在方法执行时自动开启和管理事务。通过理解 @Transactional 的工作原理,我们可以更好地理解如何自定义注解并使用 AOP 来实现类似的功能。

@Transactional 注解的元注解

@Transactional 注解本身使用了一些元注解来定义其行为和适用范围:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Transactional {// 其他属性和方法
}
  • @Target({ElementType.METHOD, ElementType.TYPE}):表示 @Transactional 注解可以应用于方法和类(包括接口和枚举)。
  • @Retention(RetentionPolicy.RUNTIME):表示 @Transactional 注解在运行时也会被保留,可以通过反射机制读取。
  • @Documented:表示使用 @Transactional 注解的元素应当被 javadoc 或类似工具文档化。

@Transactional 的属性

@Transactional 注解有许多属性,用于配置事务的行为,例如:

  • propagation:事务的传播行为(例如,REQUIRED、REQUIRES_NEW 等)。
  • isolation:事务的隔离级别(例如,READ_COMMITTED、SERIALIZABLE 等)。
  • timeout:事务的超时时间。
  • readOnly:是否为只读事务。
  • rollbackFor:指定哪些异常会触发事务回滚。
  • noRollbackFor:指定哪些异常不会触发事务回滚。

@Transactional 的工作原理

@Transactional 注解的工作原理主要依赖于 Spring AOP。Spring AOP 会拦截带有 @Transactional 注解的方法或类,并在方法执行前后管理事务的开启、提交和回滚。

自定义注解和 AOP 实现类似 @Transactional 的功能

我们可以通过自定义注解和 AOP 来实现类似 @Transactional 的功能。以下是一个示例,展示了如何创建一个自定义注解 @MyTransactional,并使用 AOP 来管理事务。

1. 创建自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface MyTransactional {// 可以添加其他属性,例如事务传播行为、隔离级别等
}

@Transactional 注解是 Spring 框架中用于声明式事务管理的核心注解。它可以应用于类或方法上,以声明该类或方法需要事务支持。通过 @Transactional 注解,Spring 可以自动管理事务的开始、提交和回滚。

@Transactional 注解的定义

@Transactional 注解的定义如下:

package org.springframework.transaction.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.TransactionAttribute;@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Transactional {@AliasFor("transactionManager")String value() default "";@AliasFor("value")String transactionManager() default "";Propagation propagation() default Propagation.REQUIRED;Isolation isolation() default Isolation.DEFAULT;int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;boolean readOnly() default false;Class<? extends Throwable>[] rollbackFor() default {};String[] rollbackForClassName() default {};Class<? extends Throwable>[] noRollbackFor() default {};String[] noRollbackForClassName() default {};
}

元注解的解释

@Retention
@Retention(RetentionPolicy.RUNTIME)
  • RetentionPolicy.RUNTIME:表示 @Transactional 注解在运行时也会被保留,可以通过反射机制读取。这对于事务管理是必要的,因为 Spring 需要在运行时动态地管理事务。
@Target
@Target({ElementType.METHOD, ElementType.TYPE})
  • ElementType.METHOD:表示 @Transactional 注解可以应用于方法。
  • ElementType.TYPE:表示 @Transactional 注解可以应用于类(包括接口和枚举)。当应用于类时,该类的所有方法都将具有事务支持,除非方法上另有声明。

@Transactional 注解的属性

  • valuetransactionManager:指定要使用的事务管理器的名称。默认情况下,使用默认的事务管理器。
  • propagation:指定事务的传播行为。默认值为 Propagation.REQUIRED,表示当前方法必须在事务中运行。如果当前没有事务,则会启动一个新的事务。
  • isolation:指定事务的隔离级别。默认值为 Isolation.DEFAULT,表示使用底层数据库的默认隔离级别。
  • timeout:指定事务的超时时间(以秒为单位)。默认值为 TransactionDefinition.TIMEOUT_DEFAULT,表示使用底层事务管理器的默认超时时间。
  • readOnly:指定事务是否为只读。默认值为 false。只读事务可以优化性能,因为数据库可以跳过某些锁定操作。
  • rollbackForrollbackForClassName:指定哪些异常会触发事务回滚。默认情况下,只有未捕获的运行时异常会触发回滚。
  • noRollbackFornoRollbackForClassName:指定哪些异常不会触发事务回滚。

使用示例

在类上使用 @Transactional
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
@Transactional
public class MyService {public void performOperation() {// 该方法将在事务中运行}
}
在方法上使用 @Transactional
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class MyService {@Transactionalpublic void performOperation() {// 该方法将在事务中运行}
}

自定义注解与 @Transactional 的对比

通过前面的自定义注解示例,我们可以看到 @Transactional 注解的实现方式与自定义注解类似。它们都使用了 @Retention@Target 元注解来定义注解的保留策略和适用范围。不同的是,@Transactional 注解还包含了多个属性,用于配置事务的行为。

总结

  • @Retention(RetentionPolicy.RUNTIME):表示 @Transactional 注解在运行时也会被保留,可以通过反射机制读取。
  • @Target({ElementType.METHOD, ElementType.TYPE}):表示 @Transactional 注解可以应用于方法和类(包括接口和枚举)。
  • 属性@Transactional 注解包含多个属性,用于配置事务的传播行为、隔离级别、超时时间、只读属性以及回滚规则。

通过理解 @Transactional 注解的定义和使用,我们可以更好地理解如何创建和使用自定义注解,并通过AOP实现类似的功能。

使用反射机制实现自定义注解

在Java中,自定义注解是一种强大的工具,用于提供额外的元数据信息。注解以@符号开头,后面紧跟注解名。下面是如何创建和使用自定义注解的步骤:

1. 创建自定义注解

创建注解非常简单,只需要定义一个Java接口,并使用@interface关键字。注解接口通常用于定义注解的元数据,如参数、默认值等。

// 创建一个自定义注解
@interface MyAnnotation {String value() default "";
}

在这个例子中,我们创建了一个名为MyAnnotation的注解,它有一个名为value的参数,参数默认值为""

2. 使用自定义注解

在类、方法、字段或参数上使用自定义注解,只需要在相应的位置使用@MyAnnotation

示例:使用自定义注解在方法上
public class ExampleClass {@MyAnnotation("example")public void myMethod() {// 方法体}
}
示例:使用自定义注解在字段上
public class ExampleClass {@MyAnnotation("example")private String myField;
}
示例:使用自定义注解在参数上
public class ExampleClass {public void myMethod(@MyAnnotation("example") String myParam) {// 方法体}
}
3. 反射操作

使用Java的反射API,可以读取类上的注解信息。

import java.lang.reflect.Method;public class AnnotationReader {public static void main(String[] args) throws Exception {ExampleClass exampleClass = new ExampleClass();Method[] methods = exampleClass.getClass().getMethods();for (Method method : methods) {MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);if (myAnnotation != null) {System.out.println("Method: " + method.getName() + ", Value: " + myAnnotation.value());}}}
}
总结

自定义注解在Java中非常有用,可以帮助开发者添加额外的元数据信息,提高代码的可读性和可维护性。通过结合注解处理器(Annotation Processing Tool,APT)和反射API,可以实现更强大的代码生成和动态行为。

相关文章:

从代理模式到注解开发

代理模式 package org.example.proxy;public class ProxyClient {public static void main(String[] args) {ProxyBuilder proxyBuilder new ProxyBuilder();proxyBuilder.build();} }interface BuildDream {void build(); }class CustomBuilder implements BuildDream {Over…...

力扣刷题(自用)

哈希 128.最长连续序列 128. 最长连续序列 - 力扣&#xff08;LeetCode&#xff09; 这个题要求O(n)的时间复杂度&#xff0c;我一开始想的是双指针算法&#xff08;因为我并不是很熟悉set容器的使用&#xff09;&#xff0c;但是双指针算法有小部分数据过不了。 题解给的哈…...

网站开发:使用VScode安装yarn包和运行前端项目

一、首先打开PowerShell-管理员身份运行ISE 输入命令&#xff1a; set-ExecutionPolicy RemoteSigned 选择“全是”&#xff0c;表示允许在本地计算机上运行由本地用户创建的脚本&#xff0c;没有报错就行了 二、接着打开VScode集成终端 输入 npm install -g yarn 再次输入以…...

Linux_线程的使用

目录 1、线程与进程的关系 2、线程的优缺点 3、创建线程 4、查看启动的线程 5、验证线程是共享地址空间的 6、pthread_create的重要形参 6.1 线程id 6.2 线程实参 7、线程等待 8、线程退出 9、线程取消 10、线程tcb 10.1 线程栈 11、创建多线程 12、__th…...

[word] word如何编写公式? #微信#知识分享

word如何编写公式&#xff1f; word如何编写公式&#xff1f;Word中数学公式是经常会使用到的&#xff0c;若是要在文档中录入一些复杂的公式&#xff0c;要怎么做呢&#xff1f;接下来小编就来给大家讲一讲具体操作&#xff0c;一起看过来吧&#xff01; 方法一&#xff1a;…...

Pytest 框架快速入门

Pytest 框架常用功能介绍 一、简介 Pytest 是一个功能强大的 Python 测试框架&#xff0c;具有简单易用、测试用例清晰易读、支持参数化、可运行由 Nose 和 unittest 编写的测试用例、拥有丰富的第三方插件且可自定义扩展、支持重复执行失败的用例以及方便与持续集成工具集成…...

抖音视频素材去哪里找啊?视频素材网站库分享

在这个视觉盛宴的抖音平台上&#xff0c;高质量和有趣的视频素材常常是吸引观众的重要钥匙。如果你也正在寻找那些能让你的视频作品更加出色的资源&#xff0c;那么恭喜你&#xff0c;今天我将为你介绍10个超实用的视频素材网站&#xff0c;让你的抖音视频创作充满创意和效率。…...

win10 langchain-chatchat-0.3.1安装及测试

git clone https://github.com/chatchat-space/Langchain-Chatchat.git conda create -n langchain3 python3.11 conda activate langchain3 xinference安装用另一篇文章的内容处理。 pip install langchain-chatchat -U -i https://pypi.tuna.tsinghua.edu.cn/simple pip in…...

Redis 教程:从入门到入坑

目录 1. Redis 安装与启动1.1. 安装 Redis1.1.1. 在Linux上安装1.1.2. 在Windows上安装 1.2. 启动 Redis1.2.1. 在Linux上启动1.2.2. 在Windows上启动 1.3. 连接Redis1.3.1. 连接本地Redis1.3.2. 连接远程Redis1.3.2.1. 服务器开放端口1.3.2.2. 关闭防火墙1.3.2.3. 修改配置文件…...

计算机图形学入门31:动画与模拟的求解

1.前言 上一篇介绍了动画与模拟的很多方法、模拟各种运动、基本知识。定义一个物体的速度和加速度&#xff0c;算出物体在任何时刻的位置&#xff0c;但是没有介绍具体怎么实现。这篇文章就是从上一篇的概念出发&#xff0c;介绍怎么把一个物体或多个物体运动的位置、不同时间出…...

Jmeter-单用户单表查询千条以上数据,前端页面分页怎么做

这里写自定义目录标题 单用户单表查询千条以上数据 单用户单表查询千条以上数据 对于单用户查询千条以上数据&#xff0c;但是前端页面做了分页的情况下 可以直接把查询接口下的分页限制去掉&#xff0c;便可查询出当前页面查询条件下的全部数据 例如去掉如下内容&#xff1…...

夏日养猫攻略!你家猫咪缺水了吗?补水罐头秘籍大公开

炎炎夏日&#xff0c;高温来袭&#xff0c;这几天又有几只猫咪因为中暑被送到我们医院了&#xff0c;经过诊断&#xff0c;发现猫咪体温超过40C&#xff0c;而且严重缺水。 各位铲屎官真的得注意&#xff0c;酷暑炎热&#xff0c;给猫咪补水很重要。猫咪的汗腺数量远远不及人类…...

生成名片格式

/*** 生成名片* param array arr2 卡片素材* param array strs 素材文字 数组* param function successFn 回调函数* * */PosterCanvasCard: function(arr2, strs, successFn, errFun) {let that this;const ctx uni.createCanvasContext(myCanvas);ctx.clearRect(0, 0, 0, 0…...

Linux常用命令(简要总结)

Linux常用命令 Linux 是一个强大的操作系统&#xff0c;广泛应用于服务器、开发和嵌入式系统中。掌握一些常用的 Linux 命令对于高效地使用系统至关重要。以下是一些常用的 Linux 命令及其简要说明&#xff1a; 文件和目录操作 ls&#xff1a;列出目录内容 ls ls -l # …...

从挑战到实战!TDengine 新能源行业研讨会要点回顾

近年来&#xff0c;随着全球对可再生能源需求的不断增长&#xff0c;新能源行业迎来了前所未有的发展机遇。然而&#xff0c;伴随着行业的快速发展&#xff0c;海量数据的管理和高效利用成为了行业面临的重要挑战。如何通过先进的数据管理技术提升新能源系统的效率和可靠性&…...

Linux 之 设置环境变量

设置环境变量 启动帐号后自动执行的是 文件为 .bashrc&#xff0c;然后通过这个文件可设置自己的环境变量&#xff1b; 临时设置环境变量&#xff1a; 在终端中使用 export 命令可以临时设置环境变量&#xff0c;例如&#xff1a;export PATH$PATH:/your/custom/path这种方法设…...

postgresql删除用户

背景 **角色与用户**&#xff1a;在 PostgreSQL 中&#xff0c;用户和组的概念是通过“角色”来统一实现的。角色可以有登录权限&#xff08;在这种情况下&#xff0c;它们通常被称为“用户”&#xff09;&#xff0c;也可以没有&#xff08;在这种情况下&#xff0c;它们通常用…...

【java深入学习第5章】Spring Boot 统一功能的实现及处理方式

Spring Boot 统一功能处理 在开发 Web 应用程序时&#xff0c;为了提高代码的可维护性和可扩展性&#xff0c;我们通常会采用一些统一的功能处理方式。本文将介绍如何在 Spring Boot 中实现统一的数据返回格式、异常处理和功能处理&#xff0c;并通过一个图书管理系统的案例来…...

【常见开源库的二次开发】基于openssl的加密与解密——单向散列函数(四)

目录&#xff1a; 目录&#xff1a; 一、什么是单项散列函数&#xff1f; 1.1 如何验证文件是否被修改过 1.2 单项散列函数&#xff1a; 二、单向hash抗碰撞 2.1 弱抗碰撞&#xff08;Weak Collision Resistance&#xff09; 2.2 强抗碰撞&#xff08;Strong Collision Resista…...

获取不重复流水号(java)

一&#xff1a;概述 很多业务场景都需要获取不重复的业务流水号&#xff0c;当微服务项目或服务多节点部署时&#xff0c;获取流水号场景使用分布式锁性能低下&#xff0c;可以基于数据库行锁实现获取不重复流水号。 二&#xff1a;创建流水号数据库 CREATE TABLE serial (i…...

【python虚拟环境管理】【mac m3】 使用pipx安装poetry

文章目录 一. 安装 pipx二. 安装Poetry1. 安装2. advanced 操作 官网文档&#xff1a;https://python-poetry.org/docs/ pipx介绍文档&#xff1a;https://blog.51cto.com/u_15064632/2570626 一. 安装 pipx pipx 用于全局安装 Python 命令行应用程序&#xff0c;同时在虚拟环…...

git使用以及理解

git练习网站 Learn Git Branching git操作大全Oh Shit, Git!?! git commit git branch name git merge bugFix 合并俩个分支 git rebase main git checkout headgit switch head 会导致HEAD分离 &#xff0c;就是指head->HEAD->c1 相对引用 ------------------- …...

openlayers 3d 地图 非三维 立体地图 行政区划裁剪 地图背景

这是实践效果 如果没有任何基础 就看这个专栏&#xff1a;http://t.csdnimg.cn/qB4w0 这个专栏里有从最简单的地图到复杂地图的示例 最终效果&#xff1a; 线上示例代码&#xff1a; 想要做这个效果 如果你的行政区划编辑点较多 可能会有卡顿感 如果出现卡顿感需要将边界点相应…...

GEO数据挖掘从数据下载处理质控到差异分析全流程分析步骤指南

0. 综合的教学视频介绍 GEO数据库挖掘分析作图全流程每晚11点在线教学直播录屏回放视频&#xff1a; https://www.bilibili.com/video/BV1rm42157CT/ GEO数据从下载到各种挖掘分析全流程详解&#xff1a; https://www.bilibili.com/video/BV1nm42157ii/ 一篇今年近期发表的转…...

‍我想我大抵是疯了,我喜欢上了写单元测试

前言 大家好我是聪。相信有不少的小伙伴喜欢写代码&#xff0c;但是对于单元测试这些反而觉得多此一举&#xff0c;想着我都在接口文档测过了&#xff01;还要写什么单元测试&#xff01;写不了一点&#xff01;&#xff01; 由于本人也是一个小小程序猿&#x1f649;&#xf…...

【Visual Studio】Visual Studio使用技巧及报错解决合集

目录 目录 一.概述 二.Visual Studio报错问题及解决方法 三.Visual Studio操作过程中遇到的问题及解决方法 四.Visual Studio编译优化选项 五.Visual Studio快捷键 一.概述 持续更新Visual Studio报错及解决方法&#xff0c;包括Visual Studio报错问题及解决方法、Visua…...

服务器数据恢复—raid5阵列热备盘同步失败导致lun不可用的数据恢复案例

服务器存储数据恢复环境&#xff1a; 华为S5300存储中有一组由16块FC硬盘组建的RAID5磁盘阵列&#xff08;包含一块热备盘&#xff09;。 服务器存储故障&#xff1a; 该存储中的RAID5阵列1块硬盘由于未知原因离线&#xff0c;热备盘上线并开始同步数据&#xff0c;数据同步到…...

算法题目整合

文章目录 121. 小红的区间翻转142. 两个字符串的最小 ASCII 删除总和143. 最长同值路径139.完美数140. 可爱串141. 好二叉树 121. 小红的区间翻转 小红拿到了两个长度为 n 的数组 a 和 b&#xff0c;她仅可以执行一次以下翻转操作&#xff1a;选择a数组中的一个区间[i, j]&…...

万界星空科技AI低代码平台:重塑数字化创新边界

在这个日新月异的数字化时代&#xff0c;技术的飞速发展正以前所未有的力量重塑着每一个行业。企业如何在瞬息万变的市场环境中保持竞争力&#xff0c;实现业务的快速迭代与创新&#xff1f; 重塑开发模式&#xff0c;加速数字化转型 传统软件开发周期长、成本高、门槛高&…...

iredmail服务器安装步骤详解!如何做配置?

iredmail服务器安全性设置指南&#xff1f;怎么升级邮件服务器&#xff1f; iredmail是一个功能强大的邮件服务器解决方案&#xff0c;它集成了多个开源软件&#xff0c;使您能够快速部署和管理邮件服务。AokSend将逐步引导您完成安装过程&#xff0c;无需深入的编程知识即可轻…...