A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 安之啊 于 2017-12-24 14:46 编辑

通过写一个工厂类BeanFactory负责创建配置文件config.properties中指定的目标类或者代理类的实例对象,类中方法getBean根据参数传入的字符串返回一个相应的实例对象,如果该类名是ProxyFactoryBean类则创建代理类的实例对象,否则直接调用目标类的不带参数的构造方法创建实例对象并返回,实现类似Spring框架的AOP功能。


BeanFactory类分析及代码

这个类主要通过构造方法传入一个输入流接收配置文件,另外一个主要方法getBean是整个框架的核心。这个方法先获取配置文件中需要创建的类的名字,然后先调用不带参数的构造方法创建一个实例对象(配置中的要求创建的类必须是JavaBean,否则不一定具有不带参数的构造方法),通过实例对象判断是否是ProxyFactoryBean对象,如果是,则转换成ProxyFactoryBean对象,调用ProxyFactoryBean类中方法getProxy来创建代理对象。


package com.anzhi.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class BeanFactory {

    Properties props = new Properties();
    public BeanFactory(InputStream ips){
        try {
            props.load(ips);//读入配置文件
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public Object getBean(String key){
        //这个方法的用途是:获得一个key所指的类对象,
        //如果这个类是ProxyFactoryBean类的,即代理类,则创建代理对象并返回
        //如果不是则直接调用不带参数的构造方法创建对象返回
        String clazzname = props.getProperty(key);
        Object bean = null;
        try {
            Class clazz = Class.forName(clazzname);
            bean = clazz.newInstance();//对于javabean必须有不带参数的构造方法
        } catch (Exception e) {
            e.printStackTrace();
        }
        if(bean instanceof ProxyFactoryBean)
        {
            //转换成ProxyFactoryBean对象,方便使用getProxy方法和set方法
            ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean)bean;
            Object proxy = null;
            try {
                //取得所想建立的对象目标和Advice类
                Object target = Class.forName(props.getProperty(key+".target")).newInstance();
                Advice ad = (Advice)Class.forName(props.getProperty(key+".advice")).newInstance();
                proxyFactoryBean.setTarget(target);
                proxyFactoryBean.setAd(ad);

                proxy = proxyFactoryBean.getProxy();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return proxy;
        }
        return bean;
    }
}
ProxyFactoryBean类分析及代码

核心是getProxy利用Proxy类的静态方法newProxyInstance创建代理对象,覆盖了invoke方法,利用InvocationHandler处理方法调用。invoke方法中间插入了Advice实现类。


package com.anzhi.test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Method;

public class ProxyFactoryBean {

    private Object target;
    private Advice ad;

    public Object getProxy() {
        //利用Proxy类的静态方法newProxyInstance创建代理对象
        Object proxyobj = Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler(){

                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        ad.beforeMethod(method);
                        Object obj = method.invoke(target, args);
                        ad.afterMethod(method);
                        return obj;
                    }
                }
        );
        return proxyobj;
    }

    public Object getTarget() {
        return target;
    }

    public void setTarget(Object target) {
        this.target = target;
    }

    public Advice getAd() {
        return ad;
    }

    public void setAd(Advice ad) {
        this.ad = ad;
    }
}
Advice接口及实现类

这个不用解释了,直接给代码,Advice接口


package com.anzhi.test;

import java.lang.reflect.Method;

public interface Advice {
    void beforeMethod(Method method);
    void afterMethod(Method method);
}
Advice实现类

        package maxwell_nc.aopframework;

        import java.lang.reflect.Method;

public class MyAdvice implements Advice {

    @Override
    public void afterMethod(Method method) {
        System.out.println(method.getName()+"_start");
    }

    @Override
    public void beforeMethod(Method method) {
        System.out.println(method.getName()+"_end");
    }

}
测试
配置文件:
这里我们用一个单独类来测试,我们先写一个config.properties文件

        #bean=java.util.ArrayList
        bean=com.anzhi.test.ProxyFactoryBean
        bean.target=java.util.ArrayList
        bean.advice=com.anzhi.test.MyAdvice
代码:
package maxwell_nc.aopframework;

import java.io.InputStream;
import java.util.Collection;

public class AopFrameworkTest {

    public static void main(String[] args) {
        InputStream ips = AopFrameworkTest.class.getResourceAsStream("config.properties");
        //创建工厂
        BeanFactory beanFactory = new BeanFactory(ips);
        //获取对象并打印对应字节码名字
        Object bean = beanFactory.getBean("bean");
        System.out.println(bean.getClass().getName());
        //下面语句可以测试Advice类是否有效
        //((Collection)bean).clear();
    }

}

1 个回复

倒序浏览
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马