java注解的原理及应用

1.什么是注解?

           注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。相信很多学过spring等框架的同学对注解一定不陌生吧!比如@Service,@Repository,@Autowired等等。就算没有学过框架,但凡你只要学了java基础,你都会接触到注解。比如一个子类继承父类的方法,该方法前面会有@Override,这个其实就是注解!


2.如何声明注解?

   使用@interface关键字就能声明一个注解。如下例:

public @interface TestAnno {

}

3.如何声明注解的生命周期和作用域?

@Target(ElementType.FIELD)	    //作用域   	FIELD表示只能作用在字段中
@Retention(RetentionPolicy.RUNTIME) //生命周期	RUNTIME表示运行时有效
@Documented				//让它定制文档化功能,使用使用此注解时必须设置RetentionPolicy为RUNTIME
@Inherited				//让它允许继承,可作用到子类
public @interface Column {
	/**
	 * 属性变量只能声明无参无异常的,当只有一个属性时,属性名称为value,
	 */
	String value();
}

ElementType中的所有值都可以作为@Column的作用域,而且作用域可以同时有多个值比如@Target(ElementType.TYPE,ElementType.FIELD)表示该注解可以作用在类上,也能作用在字段上。RetentionPolicy的取值有三个,分别是SOURCE,CLASS,RUNTIME。分别表示源码注解,注解会保留在源码中,在编译和运行时无效。编译注解,注解会保留在class文件中,编译时会识别,运行时不识别。运行时注解,注解会保留到class文件中,同时运行时也会被识别。

4.注解的应用

注解的应用十分广泛,这里只展示一小个方面来说明注解的使用原理。当我们使用数据库查询数据时,大多数时候需要我们自己来写sql语句,当我们的逻辑比较多,较复杂时,会显得非常不方便。下面将使用自定义注解实现自动拼接sql,然后自动封装查询结果

首先自定义两个注解

@Target(ElementType.FIELD)	    //作用域   	FIELD表示只能作用在字段中
@Retention(RetentionPolicy.RUNTIME) //生命周期	RUNTIME表示运行时有效
public @interface Column {
	/**
	 * 属性变量只能声明无参无异常的,当只有一个属性时,属性名称为value
	 */
	String value();
}
@Target(ElementType.TYPE)           //作用域   	TYPE表示只能作用在类中
@Retention(RetentionPolicy.RUNTIME)//生命周期	RUNTIME表示运行时有效
public @interface Table {
	/**
	 * 属性变量只能是无参无异常的,当只有一个属性时,属性名称为value
	 */
	String value();
}

创建一个javaBean

@Table("USER")
public class User implements java.io.Serializable {
	
	private static final long serialVersionUID = 1L;
	
	private int id;
	
	@Column("USER_ID")
	private String userId;			//用户ID
	
	@Column("USER_NAME")
	private String userName;		//用户名称
	
	@Column("PASSWORD")
	private String password;		//用户密码
	
	@Column("SEX")
	private String sex;				//用户性别
	
	@Column("EMAIL")
	private String email;			//电子邮件
	
	@Column("PHONE")
	private String phone;			//联系电话
	
	@Column("BIRTHDAY")
	private Date birthday;		//出生日期
	
	@Column("ADDRESS")
	private String address;			//家庭住址
	
	@Column("ACTIVE_FLAG")
	private int activeFlag=1;		//用户活跃标志:0 删除,1 活跃
	
	
	public String getUserId() {
		return userId;
	}
	public void setUserId(String userId) {
		this.userId = userId;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public String getPhone() {
		return phone;
	}
	public void setPhone(String phone) {
		this.phone = phone;
	}
	public Date getBirthday() {
		return birthday;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public int getActiveFlag() {
		return activeFlag;
	}
	public void setActiveFlag(int activeFlag) {
		this.activeFlag = activeFlag;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	
}

创建一个JdbcUtil的工具类,使用的是c3p0连接池

public class JdbcUtil {
	
	private static ComboPooledDataSource dataSource = new ComboPooledDataSource();
	
	private static Connection getConnection() {
		Connection connection = null;
		try {
			connection = dataSource.getConnection();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return connection;
	}
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static List<Object> query(Object o) {
		Class c = o.getClass();//获取类对象
		StringBuffer sb = new StringBuffer();
		boolean isExist = c.isAnnotationPresent(Table.class);//判断c中是否存在注解
		String tableName = null;
		if (isExist) {
			//获取表名
			Table table = (Table)c.getAnnotation(Table.class);
			tableName = table.value();
			sb.append("select * from ").append(tableName).append(" where 1=1");
		}
		Field[] fields = c.getDeclaredFields();
		//遍历字段名
		for (Field field:fields) {
			//判断该字段是否存在注解
			if (field.isAnnotationPresent(Column.class)) {
				//获取字段名
				Column column = field.getAnnotation(Column.class);
				String columnName = column.value();
				//获取字段值
				String fieldName = field.getName();
				String getMethodName = "get"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1);
				Object fieldValue = null;
				try {
					fieldValue = c.getMethod(getMethodName).invoke(o);
				} catch (Exception e) {
					e.printStackTrace();
				}
				//拼接sql
				if (fieldValue!=null) {
					sb.append(" and ").append(columnName).append("=");
					if (fieldValue instanceof String) {
						sb.append("'").append(fieldValue).append("'");
					}else if (fieldValue instanceof Integer) {
						sb.append(fieldValue);
					}
				}
			}
		}
		String sql = sb.toString();
		Connection connection = null;
		PreparedStatement preparedStatement = null;
		ResultSet rs = null;
		try {
			connection = getConnection();
			preparedStatement = connection.prepareStatement(sql);
			rs = preparedStatement.executeQuery();
			ResultSetMetaData rMetaData = rs.getMetaData();//获取元数据对象
			List<Object> list = new ArrayList<Object>();
			while (rs.next()) {
				Object object = c.newInstance();//通过类对象获取实例对象
				for (int i = 1; i <= rMetaData.getColumnCount(); i++) {
					Object value = rs.getObject(i);//获取该列的值
					for (int j = 0; j < fields.length; j++) {
						if (fields[j].getName().equalsIgnoreCase(rMetaData.getColumnName(i).replace("_", ""))) {
							fields[j].setAccessible(true);//私有变量,其它对象不具有访问权,故设置可访问标志为true,给fields[j]提供权限
							fields[j].set(object, value);
							fields[j].setAccessible(fields[j].isAccessible());//还原可访问标志
						}
					}
				}
				list.add(object);
			}
			return list;
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			close(connection, preparedStatement, rs);
		}
		return null;
	}
	
	private static void close(Connection connection,PreparedStatement preparedStatement,ResultSet resultSet) {
		try {
			if (connection!=null) {
				connection.close();
			}
			if (preparedStatement!=null) {
				preparedStatement.close();
			}
			if (resultSet!=null) {
				resultSet.close();
				
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

在该工具类中,query(Object o)方法就是通过反射的方式来解析注解,获取注解中的值,然后进行相应的处理

写个测试类来验证一下

public class Test {
	@org.junit.Test
	public void test1() {
		User user = new User();
		user.setUserName("tom352");
		List<Object> list = JdbcUtil.query(user);
		List<User> userList = new ArrayList<User>();
		if (list!=null && list.size()>0) {
			for (Object object : list) {
				userList.add((User)object);
			}
		}
		if (userList!=null && userList.size()>0) {
			System.out.println(userList.get(0));
		}
	}
}

输出的值为

User [id=2, userId=201805314616, userName=tom352, password=123456, sex=0, email=tom352@qq.com, phone=13679124685, birthday=1987-02-12, address=?????????????, activeFlag=1]

5.总结

现在发现是不是使用注解方便多了,这个工具类的查询方法对任何javaBean都有效,我们无需去为每个javaBean写sql语句,也无需自己去编写sql语句,只需要将参数封装到对应的javaBean中,它就能根据你的参数为你添加查询条件。当然,这只不过是实现了最简单的where查询条件,有兴趣的同学可以去研究一下如何可以实现多种复杂的查询条件。这里只是给同学们展示了一下注解的原理和应用。其实,使用注解,最关键的如何去解析它,只要这步你搞清楚了,后面的问题也就迎刃而解了。


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值