Annotation(注解)
概述:Annotation其实就是代码里的特殊标记,它运用于替代配置文件,也就是说,传统方式通过配置文件告诉类如何运行,
有了注解技术后,开发人员可以通过注解告诉类如何运行。
三种基本的Annotation:
@Override:限定重写父类方法,该注解只能用户方法
@Deprecated:用于表示某个程序元素(类,方法)已过时
@SuppressWarning:压制编译器警告
编写注解:
public @
interface 注解名{
属性可以为八大基本数据类型,枚举,注解(可以想成他的孩子,就如XML中还嵌套这其他的元素),
Class,以及他们的一维数组,例如:
String name();---->
这种情况下必须要在使用这个注解的时候写上属性名
细节:value是一个特殊的属性,当只有这一个属性的时候可以不写
String name() default "asd"
;默认值为“asd”,有了默认值得时候可以不写这个属性,使用默认值
}
元注解:元Annotation只修饰Annotation的Annotation。JDK中定义了如下的元Annotation
@Retention:只能用于修饰一个Annotation定义,用于指定该Annotation可以保留的域,@Retention包含一个RetentionPolicy类型的成员变量,通过这个变量指定元
SOURCE->CLASS->
RUNTIME(类加载器加载后)(Java程序有这三种状态:)
SOURCE:编译器直接丢掉这种策略的注释
CLASS:编译器将注解记录在CLASS文件中,当运行Java程序的时候,JVM不会保留注解,这是默认值
RUNTIME:编译器会把注解记录在CLASS文件中,当运行Java程序时,JVM会保留注解,程序可以用过反射获取注解
@Target:指定注解用户修饰类的哪个成员,@Target包含了一个名为value,类型为ElementType的成员变量(枚举)。
@Documented:用于指定被该元Annotation修饰的Annotation类会被javadoc工具提取成文档。
@Inherited:将它修饰的Annotation会具有继承性,如果某个类使用了被@Inherited修饰的Annotation,则其子类会自动具有该注解
案例:利用注解注入数据源(何如注入对象的问题):
@Retention(RetentionPolicy.RUNTIME)//这里一定不能忘记
public @
interface Inject {
String password() default "123"
;
String driverClass() default "com.mysql.jdbc.Driver"
;
String jdbcUrl() default "jdbc:mysql://localhost:3306/bookstore"
;
String user() default "root"
;
}
1
,注解在方法上:
public class BookDao {
private ComboPooledDataSource ds;
@Inject(driverClass="com.mysql.jdbc.Driver",jdbcUrl="jdbc:mysql://localhost:3306/bookstore",user="root",password="123"
)
public void setDs(ComboPooledDataSource ds) {
this.ds =
ds;
}
-------------------------------------------------------------
public class DaoFactory {
public static BookDao createBookDao(){
BookDao dao=
new BookDao();
//向dao中注入一个连接池
//解析出dao的所有属性
try {
BeanInfo info=Introspector.getBeanInfo(dao.getClass(),Object.
class);
PropertyDescriptor[] pds=
info.getPropertyDescriptors();
for(
int i=0;pds!=
null&&i<pds.length;i++
){
//得到bean的每一个属性描述器
PropertyDescriptor p=
pds[i];
Method method=p.getWriteMethod();
//得到属性的set方法
//看set方法上有没有Inject注解
Inject inject=method.getAnnotation(Inject.
class);
if(inject==
null)
continue;
Class propertyType=
p.getPropertyType();
System.out.println(propertyType);
//如有有注解,就用注解配置的信息,创建一个数据库连接池
DataSource ds=
createDataSourceByInject(inject,(DataSource) propertyType.newInstance());
method.invoke(dao,ds);
break;
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return dao;
}
}
//用注解的信息,(可能c3p0,也可能是jdcp连接池)为池配属性
private static DataSource createDataSourceByInject(Inject inject,DataSource ds) {
//获取到注解所有属性的方法
Method[] method=
inject.getClass().getMethods();
for(Method m:method){
String name=
m.getName();
System.out.println(name);
PropertyDescriptor pd=
null;
try {
pd=
new PropertyDescriptor(name,ds.getClass());
Object value=m.invoke(inject,
null);
//得到注解属性的值
pd.getWriteMethod().invoke(ds,value);
} catch (Exception e) {
continue;
}
}
return ds;
}
}
2
,注解在变量上:用暴力反射
后边的代码一样:
BookDao2 dao=
new BookDao2();
Field[] field=
dao.getClass().getDeclaredFields();
for(
int i=0;field!=
null&&i<field.length;i++
){
Field f=
field[i];
f.setAccessible(true);
Inject inject=f.getAnnotation(Inject.
class);
if(inject==
null){
continue;
}else{
DataSource datasource=
(DataSource) f.getType().newInstance();
DataSource ds=
createDataSourceByInject(inject,datasource);
f.set(dao,ds);
}
}
return dao;