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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 周玉龙 中级黑马   /  2012-7-26 23:02  /  1666 人查看  /  4 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

package com.heima.proxy;

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

public class BeanFactory {
        /**
         * @param args
         */
        public static void main(String[] args) {
                // TODO Auto-generated method stub
                InputStream ips = BeanFactory.class.getResourceAsStream("config.properties");
                BeanFactory beanFactory = new BeanFactory(ips);
                Object obj = beanFactory.getBean("xxx");
                System.out.println(obj.getClass().getName());
                System.out.println(obj.toString());               
        }

        private InputStream ips = null;
        private Properties props = new Properties();
       
        public BeanFactory(InputStream ips){
                this.ips = ips;
                try {
                        props.load(ips);
                } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
        }
       
        Object getBean(String beanName){
                Object obj = null;
                try {
                        String className = props.getProperty(beanName);//从配置文件中利用反射获取类名。
                        Class clazz = Class.forName(className);
                        obj = clazz.newInstance();
                        if(obj instanceof ProxyFactoryBean){
                                ProxyFactoryBean factoryBean = (ProxyFactoryBean)obj;
                                String adviceName = props.getProperty(beanName + ".advice");//从配置文件中利用反射获取建议类的类名。
                                String targetName = props.getProperty(beanName + ".target");//从配置文件中利用反射获取目标类类名。
                                factoryBean.setAdvice((Advice)Class.forName(adviceName).newInstance());
                                factoryBean.setTarget(Class.forName(targetName).newInstance());
                                obj = factoryBean.getProxy();
                        }
                } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
                return obj;
        }
}
代码太多我就不全贴了,就是张老师视频里面讲的那个动态代理的一个实现AOP功能的封装与配置。
工厂类BeanFactory负责创建目标类或代理类的实例对象,并通过配置文件实现切换。其getBean方法根据参数字符串返回一个相应的实例对象,
如果参数字符串在配置文件中对应的类名不是ProxyFactoryBean,则直接返回该类的实例对象,否则,返回该类实例对象的getProxy方法返回的对象。
如果是返回该类的实例对象的话,就没走getProxy()方法,就没有把目标和建议加进去。
怎么实现动态代理啊,怎么实现在调用某个方法是在其前面或者后面加入自己的advice啊?



评分

参与人数 1技术分 +1 收起 理由
韦念欣 + 1 赞一个!

查看全部评分

4 个回复

倒序浏览
所谓Dynamic Proxy是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
============
package proxy;

import java.lang.reflect.Method;

public interface Advice {

        void filting(Method method);
       
        void afterMethod(Method method);
       
}

-----
package proxy;

import java.lang.reflect.Method;

public class ProxyAdvice implements Advice{

        @Override
        public void  filting(Method method) {
                System.out.println("判断禁止添加的方法在代理的invoke方法中做了!");
                System.out.println("方法的名字是:"+ method.getName());
        }

        @Override
        public void afterMethod(Method method) {
                 System.out.println("方法调用之后的方法");               
        }

}
============这是视频里的做法吧,应该……
package proxy;

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

public class ProxyFactory {

        public ProxyFactory(){
               
        }
        public static Collection getProxy(final Collection target){
               
                Class proxyClazz = Proxy.getProxyClass(Collection.class.getClassLoader(),Collection.class);
               
                Collection proxy =(Collection) Proxy.newProxyInstance(
                                Collection.class.getClassLoader(),
                                new Class[]{Collection.class},
                                new InvocationHandler(){
                                        @Override
                                        public Object invoke(Object proxy, Method method,
                                                        Object[] args) throws Throwable {
                                                System.out.println("方法调用之前的方法");
//                                                System.out.println("方法的名字是:"+ method.getName());
                                                if(method.getName().equals("add")){
                                                        System.out.println("禁止添加!");
                                                        return false;
                                                }else{
                                                       
                                                        Object obj = method.invoke(target, args);
//                                                        System.out.println("方法调用之后的方法");
                                                        return obj;
                                                }
                                        }
                                }
                                );
                return proxy;
               
        }
       
}
红色代码的部分就相当于调用了自己定义的advice方法,只不过是写在里面罢了。
如果想写成视频里的那样,就把它分离出来写到蓝色代码的部分就行吧。

评分

参与人数 1技术分 +1 收起 理由
韦念欣 + 1 赞一个!

查看全部评分

回复 使用道具 举报
黑马高明辉 发表于 2012-7-26 23:44
所谓Dynamic Proxy是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实 ...

多谢你这么耐心的看完。
如果参数字符串在配置文件中对应的类名不是ProxyFactoryBean,则直接返回该类的实例对象,
当返回的是比如ArrayList的实例对象,那么他能用到代理吗?因为他不是接口啊。也就没有走if里面的代码
也就没有用到代理了,是吗?
回复 使用道具 举报
周玉龙 发表于 2012-7-27 09:23
多谢你这么耐心的看完。
如果参数字符串在配置文件中对应的类名不是ProxyFactoryBean,则直接返回该类的 ...

写一个类似于spring的aop框架,根据配置文件中配置的哦信息来生成相应的对象的类,如果配置文件中配置的是具体的类,则直接生成该类的对象;否则,如果是一个代理类则返回一个代理类的对象。

首先,先写BeanFactory类。用来根据配置文件的配置来获取相应类型的bean对象。

package proxy.aopFramework;


import java.io.IOException;

import java.io.InputStream;

import java.util.Properties;


import proxy.Advice;


public class BeanFactory {


Properties props = new Properties();


public BeanFactory(InputStream ips){


try {

props.load(ips);

} catch (IOException e) {

e.printStackTrace();

}

}


public Object getBean(String name){

String className = props.getProperty(name);

Object bean = null;

try {

Class clazz = Class.forName(className);

bean = clazz.newInstance();

System.out.println(bean.getClass().getName());

} catch (Exception e) {

e.printStackTrace();

}

if(bean instanceof ProxyFactoryBean){

ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean)bean;

try {

Advice advice = (Advice)Class.forName(props.getProperty(name+".advice")).newInstance();

Object target = Class.forName(props.getProperty(name+".target")).newInstance();

System.out.println(target.getClass().getName());

proxyFactoryBean.setAdvice(advice);

proxyFactoryBean.setTarget(target);

} catch (Exception e) {

e.printStackTrace();

}

Object proxy = proxyFactoryBean.getProxy();

return proxy;

}

return bean;

}

}

再写ProxyFactoryBean类,用来判断返回返回实际类型的bean还是返回代理bean。并可以对代理bean增加处理方法。

package proxy.aopFramework;


import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

import java.util.Collection;


import proxy.Advice;


public class ProxyFactoryBean {


private Object target ;

private Advice advice;


public Object getTarget() {

return target;

}


public void setTarget(Object target) {

this.target = target;

}


public Advice getAdvice() {

return advice;

}


public void setAdvice(Advice advice) {

this.advice = advice;

}


public Object getProxy() {


// Class proxyClazz = Proxy.getProxyClass(

// target.getClass().getClassLoader(), target.getClass());


Object proxy =  Proxy.newProxyInstance(

target.getClass().getClassLoader(),

target.getClass().getInterfaces() , new InvocationHandler() {


@Override

public Object invoke(Object proxy, Method method,

Object[] args) throws Throwable {

// System.out.println("方法调用之前的方法");

//  System.out.println("方法的名字是:"+ method.getName());

advice.filting(method);

if (method.getName().equals("add")) {

System.out.println("禁止添加!");

return false;

} else {

Object obj = method.invoke(target, args);

//  System.out.println("方法调用之后的方法");

advice.afterMethod(method);

return obj;

}

}

});

return proxy;

}

}

最后编写测试类和配置文件

package proxy.aopFramework;


import java.io.InputStream;


public class AopFrameworkTest {


/**

* @param args

*/

public static void main(String[] args) {


//用相对路径加载配置文件

InputStream ips = AopFrameworkTest.class.getResourceAsStream("config.properties");

System.out.println(ips);

BeanFactory bf = new BeanFactory(ips);

Object bean = bf.getBean("gmh");

System.out.println(bean.getClass().getName());

}

}

Config.properties

------------------------------

gmh=java.util.ArrayList

#gmh= proxy.aopFramework.ProxyFactoryBean

gmh.target=java.util.ArrayList

gmh.advice= proxy.ProxyAdvice

---------------------运行结果:

java.io.BufferedInputStream@c17164

java.util.ArrayList

java.util.ArrayList

说明通过BeanFactory的实例对象返回的是实际类型的bean。

======================

#gmh=java.util.ArrayList

gmh= proxy.aopFramework.ProxyFactoryBean

gmh.target=java.util.ArrayList

gmh.advice= proxy.ProxyAdvice

-----------------------------------

如上配置时,运行结果是:

java.io.BufferedInputStream@c17164

proxy.aopFramework.ProxyFactoryBean

java.util.ArrayList

$Proxy0

说明BeanFactory返回的bean对象是一个代理类。




回复 使用道具 举报
学习了  我也是对这块看不大懂
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马