javaEE-Annotation(注解)

来源:互联网 发布:代申请淘宝大v 编辑:程序博客网 时间:2024/05/20 13:37

所有注解都是类

2:所有注解类都默认是Annotation接口的子类。

       3:定义方式:

       public@interface SomeAnotation{

      

}

4:可以注解的位置

              类上

              方法上

              成员变量上。

              返回值上

              参数上

              局部变量

import org.junit.Test;@MyTestpublic class RunTest {@MyTestprivate int age;@MyTest()public void tt(@MyTest()int a){@MyTestint xx=0;}}

     5:如果定义了一个注解之后,没有说明这个注解可以注解的位置,则这个注解就可以注解在所有位置上。

       可以通过另一个注解,限制自定义的注解可以注解的位置:

              通过@Target定义某个注解可以注解的位置.



以下定义某个注解只可以注解到方法上:

import java.lang.annotation.ElementType;

import java.lang.annotation.Target;

//设定注解可以注解的位置

@Target(value={ElementType.METHOD})

public @interface MyTest {

 

}


用途

1:在编译时起到限制的作用.

public class MyServlet extends HttpServlet {

    @Override

    publicvoid doGet(ServletRequestreq,String name)

           throws ServletException,IOException {

    }

因为父类中没有这个方法所以添加了@Overried以后,就会编译出错。

2:在运行时组反射使用

junit的机制就是通过注解反射

所有类的字节码Class,Method,Field,Constractor都拥有一个方法

boolean

isAnnotationPresent(Class<? extendsAnnotation> annotationClass)
          如果指定类型的注解存在于此元素上,则返回 true,否则返回 false。

       注解存在的范围:

       一个类:Retention,用于定义注解存在的策略:

    java.lang.annotation
枚举 RetentionPolicy

三个常量:

枚举常量摘要

CLASS
          编译器将把注释记录在类文件中,但在运行时 VM 不需要保留注释。 在.class存在,在运行时擦除

 

RUNTIME
          编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。运行时存在。

 

SOURCE
          编译器要丢弃的注释。只在.java文件中存在@Overied

 

以下是经常使用的标准定义:

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)[W1] 

@Target(value={ElementType.METHOD})[W2] 

public @interface MyTest {

 

}

 

以下是myUnit的测试类:

       核心方法:

       public class MyUnit {

    public static void main(String[] args)throws Exception {

       System.err.println("请输入准备被测试的类:");

       Scanner sc = new Scanner(System.in);

       String clsName = sc.nextLine();//clsName = "cn.itcast.demo.RunTest";

       //根据类名获取这个类的字节

       Class cls = Class.forName(clsName);

       //实例化这个类,调用默认构造方法

       Object obj = cls.newInstance();

      

       //获取这个类中的所有方法

       Method[] ms = cls.getDeclaredMethods();//只获取用户定义的方法,private && public

       //cls.getMethods();获取这个类所方法,包括从父类中继承的方法

       //遍历判断某个方法上是否存在注解

       for(Method m:ms){

           boolean boo2 =m.isAnnotationPresent(MyTest.class);//false[W3] 

           if(boo2){

              if(m.getModifiers()==Modifier.PRIVATE){

                  System.err.println("这个私有的方法:"+m.getName()+",不支持运行...");

                  continue;

              }

              //运行这个方法

              m.invoke(obj);

           }

       }

 

注解的实例化

       永远都不要实例化注解类,因注解是由系统通过反射实例化的

给注解定义属性/方法

       如果某个注解需要一个标识,就给它定义一个属性.

 

       定义的方法:

@Retention(RetentionPolicy.RUNTIME)

@Target(value={ElementType.METHOD})

public @interface MyTest {

    /**

     * 对于一人注解类来说。

     * value属性是官方建议取的名称

     * value也是默认属性

     * 以下定义的属性,因为没有默认值,所以用户

     * 在使用时必须给显式的给值

     */

    public String value();

    /**

     * 定义一个拥有默认值的属性

     */

    public String name()default "NoName";

}

 

 

获取注解上的属性的值:

<A extends Annotation>
A

getAnnotation(Class<A> annotationClass)
          如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。

 

public class AnlyValueDemo {

    public static void main(String[] args)throws Exception {

       RunTest run = new RunTest();

       Method m1 = run.getClass().getMethod("bbb");

       //获取这个方法上的注解的实例

       MyTest mt = m1.getAnnotation(MyTest.class);[W1] 

       //获取这个注解上的属性的值

       String name = mt.name();

       String value = mt.value();

       System.err.println(name+","+value);

    }

}

 

 

用途:生成表结构并保存,以下是SUN公司提供的注解:

       在系统中存在很多的注解,其中有些注解是给JDBC。

       @Table – 定义一个类,这个类对应一个表-领域模型

       @Column – 定义一个类其中的某个字段

       @Id  - 定义主键

       @OnToMany

       @OneToOne

       @ManyToMany

 通过注解直接保存对象


//对应的表叫users@Table(name="users")public class User {@Columnprivate String id;@Columnprivate String name;@Columnprivate String pwd;@Columnprivate Integer age;@Column(name="address")private String addr;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPwd() {return pwd;}public void setPwd(String pwd) {this.pwd = pwd;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getAddr() {return addr;}public void setAddr(String addr) {this.addr = addr;}@Overridepublic String toString() {return "User [id=" + id + ", name=" + name + ", pwd=" + pwd + "]";}}

@Testpublic void save() throws Exception{//从前面页面接收User//User u = new User();//u.setId("U009");//u.setName("JackRose");//u.setPwd("3333");//u.setAge(89);//u.setAddr("中国");Contact c = new Contact();c.setId("AAAA");c.setName("DFSAFDS");c.setSex("1");QueryRunner run = new QueryRunner(DataSourceUtils.getDatasSource());run.save(c);}

//添加save方法/** * 对传递的bean进行分析 * 将t对象转成insert into users */public <T> T save(T t) throws Exception{//获取类Class<?> cls = t.getClass();//从这个字节码上获取name值这个就是表名Table table = cls.getAnnotation(Table.class);//获取表名String tableName = table.name();//组成insert into users(id,name,pwd) values('id',"name','');String sql = "insert into "+tableName;String cols="(";String values="values(";//获取所有声明的字段Field[] fs = cls.getDeclaredFields();//遍历所有字段for(Field f:fs){if(f.isAnnotationPresent(Column.class)){//获取列名String colName = f.getName();//获取column的对象Column col = f.getAnnotation(Column.class);if(col.name()!=null && !col.name().trim().equals("")){colName=col.name();}//获取列值f.setAccessible(true);//获取列值Object value = f.get(t);if(cols.equals("(")){cols+=colName;if(value instanceof String){values+="'"+value+"'";}else{values+=value;}}else{cols+=","+colName;if(value instanceof String){values+=",'"+value+"'";}else{values+=","+value;}}}}cols+=")";values+=")";sql = sql+cols+" "+values;System.err.println(sql);update(sql);return t;}


注解给反射用并控制事务


对所有的service进行代理。
要求:
被代理类必须要拥有接口。
代理的两个核心类:
Proxy :在内存中生成接口的子类。
InvocationHandler : 执行句柄 ,在执行代理类的方法时,此Invocationhandler会拦截所有代理类的方法。


示例:要求对List进行代理:import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.ArrayList;import java.util.List;public class ProxyDemo {public static void main(String[] args) throws Exception {//声明被代理类final List list = new ArrayList();//生成代理类Object obj = Proxy.newProxyInstance(ProxyDemo.class.getClassLoader(),new Class[]{List.class},new InvocationHandler() {public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {System.err.println("执行某个方法了:"+method.getName());//执行被代理类Object returnValue = method.invoke(list, args);return returnValue;}});//将代理类转换成接口的对象List list2 = (List) obj;list2.add("ddd");System.err.println(list2.get(0));}}

要求实现一个类可以对所有拥有接口的类都可以代理:



package cn.itcast.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * 此类不但是工具类,且还是执行句柄 * */public class MyProxy2 implements InvocationHandler {/** * 声明被代理类 */private Object src;/** * 构造 中接收这个被代理的对象 */private MyProxy2(Object src){this.src=src;}/** * 提供一个静态方法返回代理对象 */public static Object factory(Object src){Object proxyedObj = Proxy.newProxyInstance(MyProxy2.class.getClassLoader(),src.getClass().getInterfaces(),new MyProxy2(src));return proxyedObj;}/** * 实现执行拦截方法 */public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {System.err.println("执行的方法是>>>>:+"+method.getName());Object rVlaue = method.invoke(src,args);return rVlaue;}}

代理所有Service,在代理类中开始事务


1:书写工具类,使用ThreadLocal模式管理当前线程对象

public class DataSourceUtils {private static DataSource ds;//声明ThreadLocal容器对象private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();static {ds = // 默认的读取c3p0-config.xml中默认配置new ComboPooledDataSource();}public static DataSource getDatasSource() {return ds;}//提供一个返回Connection的方法public static Connection getConn(){Connection con = null;//先从tl中获取数据con = tl.get();if(con==null){try{con = getDatasSource().getConnection();//放到tltl.set(con);}catch(Exception e){e.printStackTrace();}}return con;}}

2:声明两个dao

3: 声明Service必须要拥有接口

public class TxService implements ITxService {//注入两个daoprivate Dao1 dao1 = new Dao1();private Dao2 dao2 = new Dao2();public void save(){dao1.save();dao2.save();}}

4:完成事务的代理类

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.sql.Connection;/** * 事务的代理类,可以代理任意的Service */public class TxProxy implements InvocationHandler{private Object src;//声明被代理类对象private TxProxy(Object src){//在私有的构造中给成员设置值this.src=src;}/** * 提供一个静态的方法返回代理对象 */public static Object factory(Object src){Object proxyedObj = //生成被代理类的接口的子类Proxy.newProxyInstance(TxProxy.class.getClassLoader(),src.getClass().getInterfaces(), new TxProxy(src));return proxyedObj;}/** * 以下是执行的句柄,当调用代理类的任意方法时都会调用这个方法 * 在这儿是管理事务的关键 */public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {//第一步:声明连接Connection con = null;Object returnValue = null;try{//第二步:获取连接con = DataSourceUtils.getConn();//第三步:设置事务的开始con.setAutoCommit(false);//第四步:调用目标类(被代理类)的方法returnValue = method.invoke(src, args);//第五步:调用如果成功con.commit();}catch(Exception e){con.rollback();throw e;}finally{con.close();DataSourceUtils.remove();}return returnValue;}}

5:声明Servlet并在servlet中通过代理获取到Service对象的实例

public class TxServlet extends HttpServlet {/** * 注入service的实例,必须要使用接口 */private ITxService service = (ITxService) TxProxy.factory(new TxService());public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {service.save();}}

6、修改Txproxy对某些方法开事务,某些方法不开事务

在需要事务的方法上添加事务注解。如果不需要事务,则不添加注解。import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)@Target(value=ElementType.METHOD)public @interface Tx {}给需要的方法添加注解:public interface ITxService {@Txvoid save();public void query();}以下是代理的完整代码:(如果你就操作一条sql语句,没有必要开事务,如果是查询也没有必要开事务。以下就开事务:  对一表操作2(insert|update|delete)次以上.  或是操作多个表时。)package cn.itcast.utils;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.sql.Connection;import javax.ejb.TransactionAttribute;import javax.persistence.Transient;/** * 事务的代理类,可以代理任意的Service */public class TxProxy implements InvocationHandler{private Object src;//声明被代理类对象private TxProxy(Object src){//在私有的构造中给成员设置值this.src=src;}/** * 提供一个静态的方法返回代理对象 */public static Object factory(Object src){System.err.println("0:返回代理类");Object proxyedObj = //生成被代理类的接口的子类Proxy.newProxyInstance(TxProxy.class.getClassLoader(),src.getClass().getInterfaces(), new TxProxy(src));return proxyedObj;}/** * 以下是执行的句柄,当调用代理类的任意方法时都会调用这个方法 * 在这儿是管理事务的关键 */public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {//判断是否有事务的注解if(!method.isAnnotationPresent(Tx.class)){System.err.println("没有事务的注解,用户不需要事务。直接执行目标方法");return method.invoke(src, args);}//第一步:声明连接Connection con = null;Object returnValue = null;try{//第二步:获取连接con = DataSourceUtils.getConn();//第三步:设置事务的开始System.err.println("设置事务的开始");con.setAutoCommit(false);//第四步:调用目标类(被代理类)的方法returnValue = method.invoke(src, args);//第五步:调用如果成功提交System.err.println("调用如果成功提交");con.commit();}catch(Exception e){System.err.println("调用不成功回滚");con.rollback();throw e;}finally{con.close();DataSourceUtils.remove();}return returnValue;}}


0 0
原创粉丝点击