4.java基础

反射

是在运行状态中,对于任意的一个类,都能够知道这个类的所有属性和方法,对任意一个对象都能够通过反射机制调用一个类的任意方法,这种动态获取类信息及动态调用类对象方法的功能称为java的反射机制。

我觉得上边那些话很不好理解,也不够清除,还是刨刨祖坟包。

在对象的创建过程中,要经历如下几步:

创建对象的时候首先会去先加载类信息进常量池。这样我们以后使用该类信息都可以直接从常量池中读取。

反射获取Class对象有如下几种反射:

        //method1
        try {
            Class class1 = Class.forName("java基础.Students");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //method2
        Students students = new Students("CrazyChild",18);
        Class class2 = students.getClass();
        //method3
        Class class3 = Students.class;

反射就是我们通过上面三种方式从常量池中拿到类信息并且封装成一个Class对象的过程(这个过程是由类加载器完成的)。

那么拿到他我们可以干点啥呢?可以为所欲为吗?

先创建一个对象把。有几种创建方式:

//通过Class.newInstance(),只适合无参
class2.newInstance();
//获取构造器,通过构造函数执行带参构造方法
 Constructor constructor = class2.getConstructor(String.class,Integer.class);
  Students stu = (Students) constructor.newInstance("heihei",10);

但是当使用第二种方式的时候,一定要注意,构造函数的参数必须是包装类,不能用像int这样,只能用Integer。

创建出对象就可以正常用了。我们也可以使用  方法.invoke(对象,参数)来调用这个函数。

  Students stu = (Students) constructor.newInstance("heihei",10);
  class3.getMethod("say").invoke(stu);

我们虽然可以通过getMethod获得所有方法包括私有方法,但是我们并不能使用所有方法,因为调用的时候会有权限检查,在这里就不深究了。

代理

代理可以分为静态代理、动态代理,动态代理又可以分为 jvm的动态代理 和 cglib的动态代理。像spring框架的AOP的底层就使用了动态代理的技术。

动态代理实现有两种方式1.反射生成匿名子类实现动态代理。2.直接添加字节码创建。cglib只能通过添加字节码的形式创建子类实现动态代理
那什么是代理,其实代理是一种场景,就想相亲前的互相打听,男方 ,媒人 , 女方。男方刚一开始不能直接去找人家女方谈情说爱,要通过媒人来进行沟通。当然这只是说一开始,等见过面后就用不着媒人。但是见面前还是要用媒人的。(感觉不是很恰当!)
大道理上讲代理是一种软件设计模式(场景),其目的是希望能做到代码重用。具体上讲,代理这种设计模式是通过不直接访问被代理对象的方式,而访问被代理对象的方法。(https://www.cnblogs.com/gonjan-blog/p/6685611.html

看起来很好理解,但是我觉得还是得刨一刨祖坟。

先看一个JDK生成匿名子类实现动态代理的例子:

//代理类
public class StuInvocationHandler<T> implements InvocationHandler {
    //invocationHandler持有的被代理对象
    T target;

    public StuInvocationHandler(T target) {
        this.target = target;
    }

    /**
     * proxy:代表动态代理对象
     * method:代表正在执行的方法
     * args:代表调用目标方法时传入的实参
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理执行" +method.getName() + "方法");
        //代理过程中插入监测方法,计算该方法耗时
        Object result = method.invoke(target, args);
        return result;
    }
}
//被代理的对象
public class Students implements Person{
    private int age;
    private String name;

    public int getAge() {
        return age;
    }

    public Students() {
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Students(String name,Integer age) {
        this.name=name;
        this.age = age;
    }

    public void say(){
        System.out.println(name+" "+age);
    }
    private void sing(){
        System.out.println("我是一只小小鸟");
    }
}
//测试方法
public static void main(String[] args) {
        //创建一个实例对象,这个对象是被代理的对象
        Person zhangsan = new Students("张三",10);

        //创建一个与代理对象相关联的InvocationHandler
        InvocationHandler stuHandler = new StuInvocationHandler<Person>(zhangsan);

        //创建一个代理对象stuProxy来代理zhangsan,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
        Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, stuHandler);

        stuProxy.say();
    }
InvocationHandler接口:proxy代理实例的调用处理程序实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序;在代理实例调用方法时,方法调用被编码分派到调用处理程序的invoke方法。

Proxy:是用来创建一个被代理对象的类。

解释一下下面这些代码:

 Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, stuHandler);

有三个参数,第一个参数是用来拿到类的加载器,第二个是要代理哪个对象(必须是接口),第三个参数是要交给哪个处理程序执行。

这个过程其实就是在动态的生成一个匿名子类。

在看一个通过添加字节码的形式实现动态代理:

实体类和接口不变。

public class AddByteRroxy implements InvocationHandler {

    private Object target;

    public AddByteRroxy(Object target) {
        this.target = target;
    }

    public <T> T getProxy(){
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before");
        Object result =method.invoke(target,args);
        System.out.println("after");
        return result;
    }
}
//测试方法
  public static void main(String[] args) {
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        Person  students = new AddByteRroxy(new Students()).getProxy();
        students.say();
    }

 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");这句话是至关重要的,他把生成的class文件保存到本地。

Cglib增强实现动态代理(需要使用cglib包):

public class MyAspect {
    
    public void before(){
        System.out.println("鸡首2");
    }
    
    public void after(){
        System.out.println("牛后2");
    }

}
public class UserServiceImpl {

    public void addUser() {
        System.out.println("a_proxy.b_cglib addUser");
    }

    public void updateUser() {
        System.out.println("a_proxy.b_cglib updateUser");

    }

    public void deleteUser() {

        System.out.println("a_proxy.b_cglib deleteUser");
    }

}
public class MyBeanFactory {
    
    public static UserServiceImpl createService(){
        //1 目标类
        final UserServiceImpl userService = new UserServiceImpl();
        //2切面类
        final MyAspect myAspect = new MyAspect();
        // 3.代理类 ,采用cglib,底层创建目标类的子类
        //3.1 核心类
        Enhancer enhancer = new Enhancer();
        //3.2 确定父类
        enhancer.setSuperclass(userService.getClass());
        /* 3.3 设置回调函数 , MethodInterceptor接口 等效 jdk InvocationHandler接口
         *     intercept() 等效 jdk  invoke()
         *         参数1、参数2、参数3:以invoke一样
         *         参数4:methodProxy 方法的代理
         *         
         * 
         */
        enhancer.setCallback(new MethodInterceptor(){

            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                
                //前
                myAspect.before();
                
                //执行目标类的方法
                Object obj = method.invoke(userService, args);
                // * 执行代理类的父类 ,执行目标类 (目标类和代理类 父子关系)
                methodProxy.invokeSuper(proxy, args);
                
                //后
                myAspect.after();
                
                return obj;
            }
        });
        //3.4 创建代理
        UserServiceImpl proxService = (UserServiceImpl) enhancer.create();
        
        return proxService;
    }

}

通过动态添加字节码创建子类实现动态代理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值