黑马程序员——java高新---注解、泛型等

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

 

一、注解

  什么是注解?

  答:对于过时的语句,java会提示过时了,通过@SuppressWarnings("Deprecation")可以在DOS命令行中取消提示,但Eclipse无法取消。这就是注解,相当于标记。编译器、开发工具、javac通过反射获得注解里的内容,进而明确应该做什么、不应该做什么。注解可以加在包、类、属性、方法、参数及局部变量之上。一个注解就是一个类。

  java.lang包中的注解:

    1、@SuppressWarnings 取消警告,保留到SOURCE阶段。

    2、@Deprecated 标识已过时,保留到RUNTIME阶段。

    3、@Override 覆盖父类方法,保留到SOURCE阶段。

  元注解:对注解类的注解,也可以理解为注解类的属性。元注解有2个分别是Rentention和Target。

    1、Rentention注解类

      注解的生命周期由Rentention的3种取值决定,Rentention的值是枚举RententionPolicy的值,只有3个:SOURCE、CLASS、RUNTIME。RententionPolicy.SOURCE对应Java源文件,RententionPolicy.CLASS(默值)对应class文件、RententionPolicy.RUNTIME对应内存中的字节码。

    2、Target注解类

      性质和Rentention一样,都是注解类的属性,表示注解类应该在什么位置,对那一块的数据有效。例如,@Target(ElementType.METHOD)。Target内部的值使用枚举ElementType表示,表示的主要位置有:注解、构造方法、属性、局部变量、函数、包、参数和类(默认值)。多个位置使用数组,例如,@Target({ElementType.METHOD,ElementType.TYPE})。

  注解属性:属性,给注解提供更加详细的信息。注解相当于接口,属性相当于方法。例如,@ItcastAnnotation(color="black"),给属性赋值,取值时类似调用方法,例如:System.out.println(annotation.color()); 所有的属性必须全部出现,除非有缺省值。

    1、为属性指定缺省值:

      String color() default "yellow";

    2、value属性:

      String value() default "bbb"; 当只设置value属性时,入股其他属性都采用默认值或者只有一个value属性,那么可以省略value=部分,例如:@MyAnnotation("aaa")。

    3、数组类型的属性:

      int[] arr() default {3,7,5};,MyAnnotation(arr={3,7,6}) 如果数组只有1个元素,可以不加{}。

      @Target({ElementType.METHOD,ElementType.TYPE}) 也是数组类型的属性。

    4、枚举类型的属性:

      EnumTest.TrafficLamp lamp() ;

      @MyAnnotation(lamp=EnumTest.TrafficLamp.GREEN)

    5、注解类型的属性:将一个注解类作为属性加入到另一个注解类中。

      MetaAnnotation annotationAttr() default @MetaAnnotation("xxxx");

      @MyAnnotation(annotationAttr=@MetaAnnotation(“yyy”) )

 

二、内省

  内省对应的英文全程是IntroSpector,内省可以使对对象的操作更加方便。在Java中,其作用主要针对JavaBean进行操作。

  内省的主要类:

    1、Introspector类      

    2、BeanInfo类    

    3、PropertyDescriptor类

内省操作代码:

 1 public static void main(String[] args) throws Exception {
 2 
 3         //创建Person对象
 4         Person p=new Person();
 5         String propertyName="age";
 6         Object retVal = getProperty(p, propertyName);
 7         System.out.println(retVal);
 8         
 9         Object value=7;
10         setProperty(p, propertyName, value);
11         System.out.println(getProperty(p,propertyName));
12     }
13     //Set方法
14     private static void setProperty(Object p, String propertyName, Object value)
15             throws IntrospectionException, IllegalAccessException,
16             InvocationTargetException {
17 
18         //得到p对象的属性描述器
19         PropertyDescriptor pd=new PropertyDescriptor(propertyName,p.getClass());
20 
21         //获取相应的read和write方法
22         Method setMethod=pd.getWriteMethod();
23         setMethod.invoke(p, value);
24     }
25     //Get方法
26     private static Object getProperty(Object p, String propertyName)
27             throws IntrospectionException, IllegalAccessException,
28             InvocationTargetException {
29 
30        //得到p对象的属性描述器
31         PropertyDescriptor pd=new PropertyDescriptor(propertyName,p.getClass());
32 
33        //获取相应的read和write方法
34         Method getMethod=pd.getReadMethod();
35         Object retVal=getMethod.invoke(p);
36         return retVal;
37     }

 

  ——>JavaBean

  概念:

    1、JavaBean是一种特殊的Java类,主要用于传递数据信息,这种Java类中的方法主要用于访问私有的字段,且方法符合某种特殊的命名规则。

    2、如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(ValueObject,简称VO)

    3、JavaBean的属性是根据其中的setter和getter方法来确定的,而不是根据其中的成员变量。

  如方法名为setId,则中文意思是设置Id,getId也是如此;去掉set或者get前缀,剩余部分就是属性名称。如果剩余部分的第二个字母小写,则把剩余部分改为小写。总之,一个类被当作javaBean使用时,JavaBean的属性是根据方法名推断出来的,它根本看不到java类内部的成员变量。

   好处:

    1、在Java EE开发中,经常要使用到JavaBean,很多环境就要求按JavaBean方式进行操作。

    2、JDK中提供了对JavaBean进行操作的一些API,这套API就称为内省。用内省这套api操作JavaBean比用普通类的方式更方便。对JavaBean的复杂内省操作,操作步骤:

      (1)、在IntroSpector类中有getBeanInfo(Class cls)的方法,通过此方法获取BeanInfo实例。参数是相应对象的字节码,即Class对象。

      (2)、BeanInfo类中有getPropertyDescriptors()的方法,可获取所有的JavaBean类中的属性信息,返回一个PropertyDescriptor[]。

      (3)、在通过遍历的形式,获取与想要的那个属性信息。

代码示例:

 1 private static Object getProperty(Object pt1, String propertyName)
 2         throws IntrospectionException, IllegalAccessException,
 3         InvocationTargetException {        
 4     BeanInfo beanInfo = trospector.getBeanInfo(pt1.getClass());
 5     PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
 6     Object retVal = null;
 7     for(PropertyDescriptor pd : pds){
 8         if(pd.getName().equals(propertyName))
 9         {
10             Method methodGetX = pd.getReadMethod();
11             retVal = methodGetX.invoke(pt1);
12             break;
13         }
14     }
15     return retVal;
16 }

 

  ——>BeanUtils工具包

  Beanutils包下载及添加:

    1、下载地址:http://commons.apache.org/proper/commons-beanutils/

    2、添加的两种方式:

       方式1:项目上“右键”—— Build Path —— Configure Build Path —— 选择Liberiers标签 ——AddExternal Jars—— 选择要导入的jar包。这种方式属于“本地添加”,存在的问题就是如果jar路径发生变化,项目就不能使用到这个jar包。

       方式2:在项目中建立一个lib目录,专门用于存放项目所使用到的jar工具包。将要使用到jar包复制进来。在Eclipse的Package Explorer面板中,在jar文件上点右键——选择Builder Path——Add toBiuldPath,添加完成。这样做的好处:jar随项目一起移动。

  可能出现的问题:添加beanutils工具包后,可能会出现org/apache/commons/logging/logFactory找不到。

  解决方法:下载commons-logging.jar,同beanutils添加步骤一样,添加日志jar包即可。

Beanutils应用代码:

 1 import org.apache.commons.beanutils.BeanUtils;
 2 import org.apache.commons.beanutils.PropertyUtils;
 3 public class IntroSpectorDemo {
 4     public static void main(String[] args) throws Exception {
 5         reflectPoint rp1 = new reflectPoint(3,5);
 6         String propertyName = "x";
 7         //    用BeanUtils工具包的方法
 8         System.out.println(BeanUtils.getProperty(rp1, "x"));//get
 9         BeanUtils.setProperty(rp1, "x", "9");//set
10         System.out.println(rp1.getX());
11     }
12 }

 

  BeanUtils工具包中还有一个工具类PropertyUtils,用法跟BeanUtils一样。区别在于:

    1、BeanUtils会对JavaBean的属性的类型进行转换,如属性本身是integer,会转换为String。

    2、PropertyUtils以属性本身的类型进行操作。

 

三、类加载器

  概念:用来动态加载Java类的工具,它本身也是Java类。

  作用:负责加载 Java 类的字节代码到 Java 虚拟机中。

  类别:Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类加载器负责加载特定位置的类:

    1、BootStrap(bootstrap class loader):它用来加载 Java 的核心库,是用C++代码来实现的,并不继承自java.lang.ClassLoader。

    2、ExtClassLoader(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。

    3、AppClassLoader(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过ClassLoader.getSystemClassLoader()来获取它。

类加载器关系图:

黑马程序员——java高新---注解、泛型等_第1张图片

类加载器演示,代码示例: 

1 public class ClassLoaderDemo {
2     public static void main(String[] args) {
3         System.out.println(
4                 ClassLoaderDemo.class.getClassLoader().getClass().getName()
5                 );//sun.misc.Launcher$AppClassLoader,表示由AppClassLoader加载
6         System.out.println(System.class.getClassLoader());//null,表示System这个类时由RootStrap加载的
7     }
8 }

 

  类加载器的委托机制:当Java虚拟机要加载一个类时,首先当前线程的类加载器去加载线程中的第一个类A。如果类A中引用了类B,Java虚拟机将使用加载类A的类加载器来加载类B。还可以直接调用ClassLoader.loadClass(String name)方法来指定某个类加载器去加载某个类。每个ClassLoader本身只能分别加载特定位置和目录中的类,但它们可以委托其他的类加载器去加载类,这就是类加载器的委托模式。类加载器一级级委托到BootStrap类加载器,当BootStrap无法加载当前所要加载的类时,然后才一级级回退到子类装载器去进行真正的加载。当回退到最初的类装载器时,如果它自己也不能完成类的加载,就抛出ClassNotFoundException异常。而不是再去找发起者类加载器的子类。

  自定义类加载器:自定义的类加载器的必须继承一个抽象类ClassLoader,用的是模版方法设计模式,继承并调用loadClass(Strign name)方法,复写findClass(Strign name)方法。loadClass方法内部是通过调用defineClass(String name,byte[] b, int off, int len)方法将class文件的二进制数据转成class字节码。 


练习:编写一个对文件内容进行简单加密的类加载器。

思路:

  1、编写一个程序,对传入的类进行简单加密。

  2、编写一个自己的类装载器,可实现对加密过的类进行加载和解密。

  3、调用类加载器加载类时,源程序中不能用该类名定义引用变量,因为编译器无法识别这个类。程序中除了可以使用ClassLoader.load方法之外,还可以使用设置线程的上下文类加载器或者系统类加载器,然后再使用Class.forName。

代码:

 1 import java.io.ByteArrayOutputStream;
 2 import java.io.FileInputStream;
 3 import java.io.FileOutputStream;
 4 import java.io.InputStream;
 5 import java.io.OutputStream;
 6 
 7 //定义一个类,继承ClassLoader
 8 public class MyClassLoader extends ClassLoader{
 9     private String classDir;
10     public MyClassLoader() {
11         super();
12     }
13     public MyClassLoader(String classDir) {
14         super();
15         this.classDir = classDir;
16     }
17     //向main方法传递两个参数,分别是源class文件的绝对路径和目标的相对路径
18     public static void main(String[] args) throws Exception {
19         String srcPath=args[0];
20         String destDir=args[1];
21         String destFileName=srcPath.substring(srcPath.lastIndexOf("\\")+1);
22         String destPath=destDir+"\\"+destFileName;
23         FileInputStream fis=new FileInputStream(srcPath);
24         FileOutputStream fos=new FileOutputStream(destPath);
25         cypher(fis,fos);
26         fis.close();
27         fos.close();
28     }
29     //这是简单的加密程序
30     private static void cypher(InputStream ips,OutputStream ops) throws Exception{
31         int b=-1;
32         while((b=ips.read())!=-1){
33             ops.write(b^0xff);
34         }
35         ips.close();
36         ops.close();
37     }
38     //复写父类的findClass方法
39     @Override
40     protected Class findClass(String name) throws ClassNotFoundException {
41         String classFileName=classDir+"\\"+name.substring(name.lastIndexOf(".")+1)+".class";
42         FileInputStream fis=null;
43         ByteArrayOutputStream bos=new ByteArrayOutputStream();
44         try {
45             fis=new FileInputStream(classFileName);
46             cypher(fis,bos);
47         } catch (Exception e) {
48             e.printStackTrace();
49         }
50         byte[] bytes=bos.toByteArray();
51         return defineClass(null, bytes, 0, bytes.length);
52     }
53 }

 

 

四、代理

  要为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能,例如,异常处理、日志、计算方法的运行时间、事务管理等等,如何去做?

  答:编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码。

代理架构图:

    黑马程序员——java高新---注解、泛型等_第2张图片

  代理的优点:如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类、还是代理类,这样以后很容易切换。例如,想要日志功能时就配置代理类,否则配置目标类,这样,增加系统功能很容易,以后运行一段时间后,又想去掉系统功能也很容易。

  ——>AOP

  概念:

    1、定义:交叉业务的编程问题即为面向方面的编程(Aspect oriented program ,简称AOP),AOP的目标就是要使交叉业务模块化。

    2、可以采用将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码的运行效果是一样的。

  特点:(1)使用代理技术正好可以解决这种交叉业务模块化的问题,代理是实现AOP功能的核心和关键技术。

     (2)安全,事务,日志等功能要贯穿到好多个模块中,所以,它们就是交叉业务。代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置加上系统功能代码:

    1、在调用目标方法之前

    2、在调用目标方法之后

    3、在调用目标方法前后

    4、在处理目标方法异常的catch块中

  让jvm创建动态类及其实例对象,需要给它提供哪些信息?

    1、接口提供动态类中的方法。生成的类中的方法通过让其实现哪些接口的方式进行告知;

    2、类加载器对象提供动态类的加载器。产生的类字节码必须有个关联的类加载器对象;

    3、InvocationHandler对象提供动态类中方法的代码。生成的类中的方法的代码是怎样的,也得由我们提供。把我们的代码写在一个约定好了接口对象的方法中,把对象传给它,它调用我的方法,即相当于插入了代码。提供执行代码的对象就是那个InvocationHandler对象,它是在创建动态类的实例对象的构造方法时传递进去的。

  注意:用Proxy.newInstance()方法可以直接一步就创建出代理对象。

示例代码:

 1 import java.lang.reflect.Constructor;
 2 import java.lang.reflect.Method;
 3 import java.lang.reflect.Proxy;
 4 import java.util.Collection;
 5 public class ProxyTest {
 6     /**
 7      * @param args
 8      * @throws SecurityException
 9      * @throws NoSuchMethodException
10      * @throws Exception
11      * @throws IllegalArgumentException
12      * @throws IllegalAccessException
13      * @throws InstantiationException
14      */
15     public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, Exception {
16         Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
17         System.out.println(clazzProxy1.getName());
18         
19         System.out.println("------------begin constructor list ------------");
20         Constructor[] constructors = clazzProxy1.getConstructors();
21         for(Constructor constructor : constructors){
22             String name = constructor.getName();
23             StringBuilder sb = new StringBuilder(name);
24             sb.append("(");
25             Class[] clazzParams = constructor.getParameterTypes();
26             for(Class clazzParam : clazzParams ){
27                 sb.append(clazzParam.getName()).append(",");
28             }
29             if( clazzParams!=null && clazzParams.length!=0)
30                 sb.deleteCharAt(sb.length()-1);
31             sb.append(")");
32             System.out.println(sb);
33         }
34         
35         System.out.println("------------begin method list -------------");
36         Method[] methods = clazzProxy1.getMethods();
37         for(Method method : methods){
38             String name = method.getName();
39             StringBuilder sb = new StringBuilder(name);
40             sb.append("(");
41             Class[] clazzParams = method.getParameterTypes();
42             for(Class clazzParam : clazzParams ){
43                 sb.append(clazzParam.getName()).append(",");
44             }
45             if( clazzParams!=null && clazzParams.length!=0)
46                 sb.deleteCharAt(sb.length()-1);
47             sb.append(")");
48             System.out.println(sb);
49         }
50     }
51 }

   让动态生成的类成为目标类的代理:

    1、直接在InvocationHandler实现类中创建目标类的实例对象

    2、为InvocationHandler实现类注入目标类的实例对象

    3、让匿名的InvocationHandler实现类访问外面方法中的目标类实例对象的final类型的引用变量。

动态代理原理图:

        黑马程序员——java高新---注解、泛型等_第3张图片

代码示例:

 1 import java.lang.reflect.Constructor;
 2 import java.lang.reflect.InvocationHandler;
 3 import java.lang.reflect.Method;
 4 import java.lang.reflect.Proxy;
 5 import java.util.ArrayList;
 6 import java.util.Collection;
 7 public class ProxyTest {
 8     /**
 9      * @param args
10      * @throws SecurityException
11      * @throws NoSuchMethodException
12      * @throws Exception
13      * @throws IllegalArgumentException
14      * @throws IllegalAccessException
15      * @throws InstantiationException
16      */
17     public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, Exception {
18         Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
19         Constructor constructor = clazzProxy1.getConstructor(InvocationHandler.class);
20 
21         System.out.println("------------begin create instance list --------------");
22         //System.out.println("------------方式一:创建动态类的实例对象 ----------");
23         class MyInvocationHandler1 implements InvocationHandler{
24             @Override
25             public Object invoke(Object proxy, Method method, Object[] args)
26                     throws Throwable {
27                 // TODO Auto-generated method stub
28                 return null;
29             }
30         }
31         Collection proxy1 = (Collection)constructor.newInstance(new MyInvocationHandler1());
32         System.out.println(proxy1);
33 
34         // System.out.println("------------方式二:创建动态类的实例对象 -----------");
35         Collection proxy2 = (Collection)constructor.newInstance(new InvocationHandler(){
36             @Override
37             public Object invoke(Object proxy, Method method, Object[] args)
38                     throws Throwable {
39                 // TODO Auto-generated method stub
40                 return null;
41             }
42         });
43 
44         // System.out.println("------------方式三:创建动态类的实例对象 ------------");
45         Collection proxy3 = (Collection)Proxy.newProxyInstance(
46                 Collection.class.getClassLoader(),
47                 new Class[]{Collection.class},
48                 new InvocationHandler(){
49                     ArrayList target = new ArrayList();
50                     @Override
51                     public Object invoke(Object proxy, Method method,
52                             Object[] args) throws Throwable {
53                         long beginTime = System.currentTimeMillis();
54                         Object retVal = method.invoke(target, args);
55                         long endTime = System.currentTimeMillis();
56                         System.out.println(method.getName()+"run time"+(endTime-beginTime));
57                         return retVal;
58                     }
59                 }
60                 );
61         proxy3.add("zxx");
62         proxy3.add("flx");
63         proxy3.add("lhm");
64         proxy3.add("bxd");
65         proxy3.add("yzz");        
66         System.out.println(proxy3.size());
67     }
68 }

 

    ——>实现类似spring的可配置的AOP框架

  工厂类BeanFactory :

     1、工厂类BeanFactory:负责创建目标类或代理类的实例对象,并通过配置文件实现切换。 

     2、getBean方法:根据参数字符串返回一个相应的实例对象。如果参数字符串在配置文件中对应的类名不是ProxyFactoryBean,则直接返回该类的实例对象,否则返回该类示例对象的getProxy方法返回的对象。 

     3、BeanFactory的构造方法:接收代表配置文件的输入流对象的配置文件。 

     4、ProxyFactoryBean为BeanFactory提供配置参数信息:(1)目标(target)(2)通告(advice) 

     5、BeanFactory和ProxyFactoryBean: 

       (1)BeanFactory是一个纯粹的bean工程,就是创建bean即相应的对象的工厂。 

       (2)ProxyfactoryBean是BeanFactory中的一个特殊的Bean,是创建代理的工厂。 

  实现类似spring的可配置的AOP框架的思路: 

     1、创建BeanFactory类: 

       (1)构造方法:接受一个配置文件,通过Properties对象加载InputStream流对象。 

       (2)创建getBean(String name)方法:根据类名name,拿到对应的类名className。 

       (3)根据类名获取其字节码对象,并创建实例对象bean。 

       (4)判断bean是否是特殊的Bean即ProxyFactoryBean。 

          △ 如果是,就要创建代理类,并设置目标(target)和通告(advice),分别得到各自的实例对象,并返回代理类实例对象。 

          △ 如果不是在返回Bean对象自己。 

     2、创建ProxyFactoryBean类,定义target和advice;定义getProxy()方法,用于创建代理类对象。 

     3、创建配置文件config.properties,对配置文件进行配置,配置内容如下 

        xxx=java.util.ArrayList 

        #xxx=cn.itheima.day3.aopframework.ProxyFactoryBean 

        xxx.advice=cn.itheima.day3.MyAdvice 

        xxx.target=java.util.ArrayList 

        注: #表示注释当前行。 

     4、作一个测试类:AopFrameworkTest进行测试。 

代码示例 :

1、创建BeanFactory类: 

 1 package cn.itheima.day3.aopframework;
 2 
 3 import java.io.IOException;
 4 import java.io.InputStream;
 5 import java.util.Properties;
 6 import cn.itheima.day3.Advice;
 7 public class BeanFactory {
 8     Properties props = new Properties();
 9     public BeanFactory(InputStream ips){
10         try {
11             props.load(ips);
12         } catch (IOException e) {
13             e.printStackTrace();
14         }
15     }
16     public Object getBean(String name){
17         String className = props.getProperty(name);//根据类名name,拿到对应的类名。
18         Object bean = null;
19         try {
20             Class clazz = Class.forName(className);
21             bean = clazz.newInstance();
22         } catch (Exception e) {
23             e.printStackTrace();
24         }
25         if(bean instanceof ProxyFactoryBean){
26             Object proxy = null;
27             ProxyFactoryBean ProxyFactoryBean = (ProxyFactoryBean)bean;
28             try {
29                 Advice advice = (Advice)Class.forName(props.getProperty(name+".advice")).newInstance();
30                 Object target = Class.forName(props.getProperty(name+".target")).newInstance();
31                 ProxyFactoryBean.setAdvice(advice);
32                 ProxyFactoryBean.setTarget(target);
33                 proxy = ProxyFactoryBean.getProxy();
34             } catch (Exception e) {
35                 e.printStackTrace();
36             }
37             return proxy;
38         }
39         return bean;
40     }
41 }

 

2、创建ProxyFactoryBean类:

 1 package cn.itheima.day3.aopframework;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 import java.lang.reflect.Proxy;
 6 import cn.itheima.day3.Advice;
 7 public class ProxyFactoryBean {
 8     private Advice advice;
 9     private Object target;
10     public Advice getAdvice() {
11         return advice;
12     }
13     public void setAdvice(Advice advice) {
14         this.advice = advice;
15     }
16     public Object getTarget() {
17         return target;
18     }
19     public void setTarget(Object target) {
20         this.target = target;
21     }
22     public Object getProxy() {
23         Object proxy3 = Proxy.newProxyInstance(                
24                 target.getClass().getClassLoader(),    //    代理类的类加载器与目标类的类加载器相同,与目标类有关。
25                 target.getClass().getInterfaces(),        //与target实现相同的接口,代理类要实现的接口也是目标类实现的接口,与目标类有关
26                 
27                 new InvocationHandler(){    //第三个参数
28                     @Override
29                     public Object invoke(Object proxy, Method method,
30                             Object[] args) throws Throwable {
31                         advice.beforeMethod(method);
32                         Object retVal = method.invoke(target, args);
33                         advice.afterMethod(method);
34                         return retVal;
35                     }
36                 }
37                 );
38         return proxy3;
39     }
40 }

 

3、创建配置文件config.properties:

xxx=java.util.ArrayList
#xxx=cn.itheima.day3.aopframework.ProxyFactoryBean
xxx.advice=cn.itheima.day3.MyAdvice
xxx.target=java.util.ArrayList

4、创建AopFrameworkTest测试类,进行测试:

 1 package cn.itheima.day3.aopframework;
 2 
 3 import java.io.InputStream;
 4 public class AopFrameworkTest {
 5     /**
 6      * @param args
 7      */
 8     public static void main(String[] args) {
 9         // TODO Auto-generated method stub
10         InputStream ips = AopFrameworkTest.class.getResourceAsStream("config.properties");
11         Object bean = new BeanFactory(ips).getBean("xxx");
12         System.out.println(bean.getClass().getName());
13     }
14 }

5、设计Advice及其子类MyAdvice:

 1 package cn.itheima.day3;
 2  import java.lang.reflect.Method;
 3  public interface Advice {    
 4      void beforeMethod(Method method);
 5      void afterMethod(Method method);
 6  }
 7 
 8 package cn.itheima.day3;
 9 import java.lang.reflect.Method;
10 public class MyAdvice implements Advice {
11     long beginTime = 0;
12     public void beforeMethod(Method method) {
13         // TODO Auto-generated method stub
14         System.out.println("到黑马程序员训练营来学习了!");
15         beginTime = System.currentTimeMillis();    //将系统功能抽取为一个对象
16     }
17 
18     public void afterMethod(Method method) {
19         // TODO Auto-generated method stub
20         System.out.println("从黑马程序员训练营毕业工作了!");
21         long endTime = System.currentTimeMillis();    //将系统功能抽取为一个对象    
22         System.out.println(method.getName()+" method run of time "+(endTime-beginTime));
23         System.out.print(System.lineSeparator() );
24     }
25 }

 

转载于:https://www.cnblogs.com/shadowW-W/p/4660275.html

你可能感兴趣的:(黑马程序员——java高新---注解、泛型等)