Java Annotation(注解)
-
java jdk5.0 引入的一种元数据。它本身不影响代码逻辑
-
可以用于标记、说明、配置,结合反射实现功能
-
常用注解:
-
@Override
-
@Deprecated
-
核心概念
什么是注解
注解是代码的标签或标记,可以附加在类、方法、属性、构造器、包、方法参数…
它不是代码本身,不直接执行逻辑
它可以被编译器、jvm、框架读取并解析
注解本质:注解就是一个特殊的接口
核心原理
注解本质
注解在Java语言中,本质是:
public interface MyAnnotation extends Annotation{ //注解内容}public @interface MyAnnotation{ //注解内容}生命周期(@Retention)
RetentionPolicy.SOURCE:仅限源码阶段,编译后丢弃
RetentionPolicy.CLASS:编译到class字节码文件中,但JVM运行时不加载
RetentionPolicy.RUNTIME:运行时保留,可以通过反射读取
作用目标(@Target)
ElementType.TYPE:类、接口、枚举
ElementType.METHOD:方法
ElementType.FIELD:属性
ElementType.PARAMETER:方法参数
ElementType.CONSTRUCTOR:构造器ElementType.ANNOTATION_TYPE:注解本身
注解解析原理
编译期解析:编译器读取注解,生成代码/校验
运行期解析:反射读取注解信息,动态执行逻辑
90%的框架都是靠反射+运行时注解实现功能
入门示例
第一步:定义一个注解
//设置注解的生命周期(运行时注解)@Retention(RetentionPolicy.RUNTIME)//设置注解的作用目标(谁能用)@Target({ElementType.TYPE,ElementType.METHOD})public @interface MyAnntation { String value() default ""; int age() default 18; String[] tags() default {};}第二步:使用注解
@MyAnntation(value = "用户类",age = 20,tags = {"测试","业务"})public class User { @MyAnntation("打印方法") public void print(){ System.out.println("执行print打印方法..."); }}第三步:反射+运行时注解(重点)
public class DemoTest { public static void main(String[] args) throws NoSuchMethodException { //1、获取User类的类实例 Class tClass=User.class; //2、验证类实例的注解实例是否是MyAnntation.class if(tClass.isAnnotationPresent(MyAnntation.class)){ MyAnntation myAnntation = (MyAnntation) tClass.getAnnotation(MyAnntation.class); System.out.println("value值:"+myAnntation.value()); System.out.println("age值:"+myAnntation.age()); System.out.println("tags值:"+ Arrays.toString(myAnntation.tags()));
Method method = tClass.getMethod("print"); MyAnntation annotation = method.getAnnotation(MyAnntation.class); System.out.println("方法注解数据:"+annotation.value()); }
}}小结
注解不会对类业务逻辑进行个修改 常用的注解形式:运行时注解 本质:对类添加额外的数据信息,通过额外的数据信息进行业务操作
自定义权限校验(模拟 Spring Security)
场景说明:接口需要登录/管理员权限才能访问,用注解统一控制
第一步:定义权限注解
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface RequirePermission { //需要的权限字符串 String value();}第二步:定义业务接口
public class OrderService { //管理员才能删除订单 @RequirePermission("order:delete") public void deleteOrder(Long id){ System.out.println("删除订单:"+id); }}第三步:拦截器解析权限
public class PermissionInterceptor { //模拟当前用户权限 private static String currentUserPermission="order:delete1"; public static void invodeMethod(Object object, Method method) throws InvocationTargetException, IllegalAccessException { //检查方法是否有权限注解 if(method.isAnnotationPresent(RequirePermission.class)){ RequirePermission anno = method.getAnnotation(RequirePermission.class); String needPermission= anno.value(); //判断权限 if(!needPermission.equals(currentUserPermission)) throw new RuntimeException("权限不足,需要:"+needPermission+",的权限"); method.invoke(object,10L); } }
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { OrderService orderService = new OrderService(); Method method = orderService.getClass().getMethod("deleteOrder", Long.class); invodeMethod(orderService,method); }}Java注解操作JDBC
核心思路:自定义注解标签说明数据库信息(表名、字段名、主键),通过反射+注解,自动封装SQL,完成对数据库的操作
整体结构
自定义表注解、字段注解
实体类绑定注解映射数据表信息
通过JDBC工具类,读取注解并拼接SQL
测试增删查的业务
自定义映射注解
表名注解
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface Table { String value();}字段注解
@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface Column { String value();}数据库实体类绑定注解
@Table("book")public class MyBook { @Column("id") private Integer book_id; @Column("isbn") private Integer book_isbn; @Column("name") private String book_name; @Column("price") private Integer book_price; //无参、有参构造器... //setter、getter方法... //toString方法...}JDBC连接工具
public class DBUtil { private static Connection conn; static { try { Class.forName("com.mysql.cj.jdbc.Driver"); conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/java2506", "root", "1234" ); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } catch (SQLException e) { throw new RuntimeException(e); } }
public static Connection getConnection(){ return conn; } }注解解析+通用JDBC工具
核心思路:读取类上@Table、属性上@Column,自动拼接SQL命令
import com.mysql.cj.xdevapi.Table;
import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;import java.util.List;
public class AnnoJdbcUtil { public static int insert(Object entity) throws IllegalAccessException {//获取实体类的类实例 Class tClass = entity.getClass();//读取数据表名称 Table table = (Table) tClass.getAnnotation(Table.class);//获取类实例注解(表名) String tableName = table.value();//获取所有属性实例对象 Field[] fields = tClass.getDeclaredFields();//创建存储字段名称和对应数据的集合(必须是有序集合) List<String> columns = new ArrayList<>(); List<Object> values = new ArrayList<>(); //循环所有属性实例对象 for (Field field : fields) { Column column = field.getAnnotation(Column.class); //如果属性实例对象没有注解,则跳过 if (column == null) continue; //存储注解中的数据表字段名称 columns.add(column.value()); //解保护私有属性成员 field.setAccessible(true); //存储私有属性成员数据 values.add(field.get(entity)); } //拼接SQL命令( insert into 表名(字段1,字段2,...,字段N) values(值1,值2,...,值N)) String cols = String.join(",", columns); StringBuffer placeholder = new StringBuffer(); for (int i = 0; i < columns.size(); i++) { placeholder.append("?"); if (i != columns.size() - 1) placeholder.append(","); } String sql = "insert into " + tableName + "(" + cols + ") values("+placeholder+") "; System.out.println(" 拼接SQL命令: "+sql); //执行JDBC try(PreparedStatement ps = DBUtil.getConnection().prepareStatement(sql)){ for (int i = 0; i < values.size(); i++) { ps.setObject(i + 1, values.get(i)); } return ps.executeUpdate(); } catch(SQLException e){ throw new RuntimeException(e); } }
public static <T> T getById(Class<T> tClass, Integer id) { Table tableAnno = tClass.getAnnotation(Table.class); String tableName = tableAnno.value(); Field[] fields = tClass.getDeclaredFields(); //拼接SQL查询命令(select id,isbn,name,price from book where id=10) StringBuffer sqlCols = new StringBuffer(); String primaryCol = null; for (Field field : fields) { Column colAnno = field.getAnnotation(Column.class); if (colAnno == null) continue; sqlCols.append(colAnno.value()).append(","); //根据id主键查询数据 if ("id".equals(colAnno.value())) primaryCol = colAnno.value(); } String selectSql = sqlCols.substring(0, sqlCols.length() - 1); String sql = "select " + selectSql + " from " + tableName + " where " + primaryCol + "=?"; try (PreparedStatement ps = DBUtil.getConnection().prepareStatement(sql)) { ps.setObject(1, id); ResultSet rs = ps.executeQuery(); T entity = null; if (rs.next()) { entity = tClass.newInstance(); //反射赋值 for (Field field : fields) { Column colAnno = field.getAnnotation(Column.class); if (colAnno == null) continue; field.setAccessible(true); field.set(entity, rs.getObject(colAnno.value())); } } return entity; } catch (SQLException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } }}测试调用
public class JdbcAnnoTest { public static void main(String[] args) throws IllegalAccessException { MyBook myBook1 = new MyBook(6,1006,"Java 反射与注解程序设计",66); int row = AnnoJdbcUtil.insert(myBook1); System.out.println("受影响行:"+row);
MyBook myBook2 = AnnoJdbcUtil.getById(MyBook.class,6); System.out.println("查询结果:"+myBook2); } }MySQL基础
Related articles
部分信息可能已经过时