精华内容
下载资源
问答
  • Java动态生成类以及动态添加属性

    万次阅读 2017-11-18 16:14:20
    有个技术实现需求:动态生成类,其中类中的属性来自参数对象中的全部属性以及来自参数对象properties文件。 那么技术实现支持:使用CGLib代理。 具体的实现步骤: 1.配置Maven文件: xmlns:xsi=...

    有个技术实现需求:动态生成类,其中类中的属性来自参数对象中的全部属性以及来自参数对象properties文件。

    那么技术实现支持:使用CGLib代理。

    具体的实现步骤:

    1.配置Maven文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.journey</groupId>
        <artifactId>journey</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <dependencies>
            <dependency>
                <groupId>cglib</groupId>
                <artifactId>cglib</artifactId>
                <version>2.2.2</version>
            </dependency>
        </dependencies>
    
    </project>

    2.封装的cglib类

    package com.journey;
    
    import net.sf.cglib.beans.BeanGenerator;
    import net.sf.cglib.beans.BeanMap;
    
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Set;
    
    /**
     * Created by little_eleventh_wolf on 2017/11/18.
     */
    public class DynamicBean {
        private Object object = null; //动态生成的类
        private BeanMap beanMap = null; //存放属性名称以及属性的类型
    
        public DynamicBean() {
            super();
        }
    
        public DynamicBean(Map propertyMap) {
            this.object = generateBean(propertyMap);
            this.beanMap = BeanMap.create(this.object);
        }
    
        /**
         * @param propertyMap
         * @return
         */
        private Object generateBean(Map propertyMap) {
            BeanGenerator generator = new BeanGenerator();
            Set keySet = propertyMap.keySet();
            for(Iterator i = keySet.iterator(); i.hasNext(); ) {
                String key = (String) i.next();
                generator.addProperty(key, (Class) propertyMap.get(key));
            }
            return generator.create();
        }
    
        /**
         * 给bean属性赋值
         * @param property 属性名
         * @param value 值
         */
        public void setValue(Object property, Object value) {
            beanMap.put(property, value);
        }
    
        /**
         * 通过属性名得到属性值
         * @param property 属性名
         * @return 值
         */
        public Object getValue(String property) {
            return beanMap.get(property);
        }
    
        /**
         * 得到该实体bean对象
         * @return
         */
        public Object getObject() {
            return this.object;
        }
    }

    3.需求的实现类:

    package com.journey;
    
    import java.beans.BeanInfo;
    import java.beans.Introspector;
    import java.beans.PropertyDescriptor;
    import java.io.InputStream;
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Properties;
    import java.util.Set;
    
    /**
     * Created by little_eleventh_wolf on 2017/11/18.
     */
    public class ClassUtil {
        private String filePath = "/config/"; //配置文件路径
    
        public String getFilePath() {
            return filePath;
        }
    
        public void setFilePath(String filePath) {
            this.filePath = filePath;
        }
    
        public Object dynamicClass(Object object) throws Exception {
            HashMap returnMap = new HashMap();
            HashMap typeMap = new HashMap();
            //读取配置文件
            Properties prop = new Properties();
            String sourcepackage = object.getClass().getName();
            String classname = sourcepackage.substring(sourcepackage.lastIndexOf(".") + 1);
            InputStream in = ClassUtil.class.getResourceAsStream(filePath + classname + ".properties");
            prop.load(in);
    
            Set<String> keylist = prop.stringPropertyNames();
    
            Class type = object.getClass();
            BeanInfo beanInfo = Introspector.getBeanInfo(type);
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for(int i = 0; i < propertyDescriptors.length; i++) {
                PropertyDescriptor descriptor = propertyDescriptors[i];
                String propertyName = descriptor.getName();
                if(!propertyName.equals("class")) {
                    Method readMethod = descriptor.getReadMethod();
                    Object result = readMethod.invoke(object, new Object[0]);
                    if(result != null) {
                        returnMap.put(propertyName, result);
                    } else {
                        returnMap.put(propertyName, "");
                    }
                    typeMap.put(propertyName, descriptor.getPropertyType());
                }
            }
            //加载配置文件中的属性
            Iterator<String> iterator = keylist.iterator();
            while(iterator.hasNext()) {
                String key = iterator.next();
                returnMap.put(key, prop.getProperty(key));
                typeMap.put(key, Class.forName("java.lang.String"));
            }
            //map转换成实体对象
            DynamicBean bean = new DynamicBean(typeMap);
            //赋值
            Set keys = typeMap.keySet();
            for(Iterator it = keys.iterator(); it.hasNext(); ) {
                String key = (String) it.next();
                bean.setValue(key, returnMap.get(key));
            }
            Object obj = bean.getObject();
            return obj;
        }
    
        public static void main(String[] args) throws Exception {
            new ClassUtil().dynamicClass(new LeapRole()/*LeapRole是个普通类,未贴源码*/);
        }
    }

    4.技术实现目的:前台框架表格数据源实际上就是带有数据的实体,但是grid中数据的类型、以及是否可见、toolbar工具栏上的按钮、是否分页,是针对实体而言,所以目前把这些信息作为实体的配置文件。在展示页面之前,读取全部信息,转为参数对象的完整对象。


    展开全文
  • 一、何为动态代理?  建议看动态代理前,先看看反射 点击这里  先看一个小案例,假设有咖啡类A,B,C。有添加物类a,b,c,。现在对咖啡类进行增强。( 比如像向啡中加糖,牛奶等这个意思)。  对一个类进行增强可以...

    一、何为动态代理?

        建议看动态代理前,先看看反射 点击这里

      先看一个小案例,假设有咖啡类A,B,C。有添加物类a,b,c,。现在对咖啡类进行增强。( 比如像向啡中加糖,牛奶等这个意思)。

      对一个类进行增强可以有三种方式:

      1.继承,可以直接继承父类的属性和方法,在新增自己的属性和方法。那么我们对每种咖啡进行增强,一共需要写3*3个继承类来完成。增强的对象和内容都不可变。

      2.装饰者模式,在需要增强的类中组合一个需要增强的属性。那么我们需要写三个组合咖啡类,每个类都添加一个添加物接口属性,向添加物接口传不同的实现就可以对该咖啡类进行不同的增强。增强的内容可变,但增强的对象是不可变的。

      3.动态代理,通过一个代理工厂,向其传入需要增强的咖啡类和添加物类,其自动生成一个增强后的代理类。我们只需要实现代理工厂这个类即可。

    二、java动态代理的实现

      java中有一个类Proxy,其有一个静态方法Object proxy = Proxy.newProxyInstance(ClassLoader classLoader , Class[] interfaces , InvocationHandler); 通过此方法就可以得到一个代理对象。下面说一下这三个参数。

      ClassLoader 类加载器,负责加载代理的类加载器。关于类加载器详细解答 点击这里

      Class[] 目标类所实现的接口们,用Class对象数组表示。

      Invocationhandler 处理器,当调用代理类proxy的方法时,实际上是调用处理器的 invoke()方法。下面在对invoke方法进行详解。

      Object invoke(Object proxy , Method method , Object[] args ) ;

      proxy:代理对象。  method: 执行的代理对象的方法。 args: 调用代理对象的方法时传入的参数。

      下面贴代码实现

    目标类接口

    package cn.edu;
    
    public interface Waiter {
    
        public void server();
    }

     

    前置通知接口

    package cn.edu;
    
    public interface AdviceBefore {
    
        public void before();
    }

    后置通知接口

    package cn.edu;
    
    public interface AdviceAfter {
    
        public void after();
    }

    代理工厂

    package cn.edu;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * 代理工厂,用于生产代理对象
     * 
     * @author WangHang
     *
     */
    public class ProxyFactory {
    
        private Object target;               // 目标对象
    
        private AdviceBefore adviceBefore;   // 前置通知
    
        private AdviceAfter adviceAfter;     // 后置通知
    
        // 生成代理对象核心方法
        public Object getProxyInstance() {
    
            ClassLoader loader = ProxyFactory.class.getClassLoader();    // 类加载器
            Class[] interfaces = target.getClass().getInterfaces();      // 类所实现的接口
    
            InvocationHandler h = new InvocationHandler() {              // 处理器
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    if (adviceBefore != null) {
                        adviceBefore.before();                           // 调用前置通知
                    }
                    Object result = method.invoke(target, args);         // 调用目标方法
                    if (adviceAfter != null) {                           // 调用后置通知
                        adviceAfter.after();
                    }
                    return result;
                }
            };
    
            Object proxy = Proxy.newProxyInstance(loader, interfaces, h); // 通过给定的三个参数生成动态代理对象
            return proxy;                                                 // 返回代理对象
        }
    
        public AdviceBefore getAdviceBefore() {
            return adviceBefore;
        }
    
        public void setAdviceBefore(AdviceBefore adviceBefore) {
            this.adviceBefore = adviceBefore;
        }
    
        public AdviceAfter getAdviceAfter() {
            return adviceAfter;
        }
    
        public void setAdviceAfter(AdviceAfter adviceAfter) {
            this.adviceAfter = adviceAfter;
        }
    
        public Object getTarget() {
            return target;
        }
    
        public void setTarget(Object target) {
            this.target = target;
        }
    
    }

    测试,接口的实现用的匿名内部类

    package cn.edu;
    
    import org.junit.Test;
    
    public class ProxyTest {
    
        @Test
        public void fun() {
            Waiter waiter = new Waiter() {                         //生成目标对象
                @Override
                public void server() {
                    System.out.println("服务中。。。");
                }
            };
            
            AdviceBefore before = new AdviceBefore() {             //生成前置通知
                @Override
                public void before() {
                    System.out.println("欢迎光临!");
                }
            };
            
            AdviceAfter after = new AdviceAfter() {
                @Override
                public void after() {
                    System.out.println("谢谢光临!");                //生成后置通知
                }
            };
            
            ProxyFactory proxyFactory = new ProxyFactory();        //生成工厂
            
            proxyFactory.setTarget(waiter);                          //设置目标对象
            proxyFactory.setAdviceBefore(before);                    //设置前置通知
            proxyFactory.setAdviceAfter(after);                      //设置后置通知
            
            Waiter proxy = (Waiter)proxyFactory.getProxyInstance();  //获得代理对象
            
            proxy.server();                                          //调用目标对象的方法
        }
        
    }

    运行结果:

    三、cglib动态代理的实现

       java动态代理的实现要求目标类实现接口,如果没有接口就无法完成动态代理。cglib(Code Genaration Liarbry)是一个强大的Code生成类库 ,它可以在程序运行期间扩展Java类。它不要求目标类实现接口,它采用的是继承的方式来扩展目标类。

      下面用cglib实现代理,其余类不用变,只需更改代理工厂,并且给Waiter添加一个实现类WaiterImpl,cglib代理是需要类的,用匿名类是会报错的。更改的部分如下。

    Waiter实现类

    package cn.edu.cglibProxy;
    
    public class WaiterImpl implements Waiter {
    
        @Override
        public void server() {
            // TODO Auto-generated method stub
            System.out.println("服务中。。。");
        }
    
    }

    代理工厂类

    package cn.edu.cglibProxy;
    
    import java.lang.reflect.Method;
    
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;
    
    /**
     * 代理工厂,用于生产代理对象
     * 
     * @author WangHang
     *
     */
    public class ProxyFactory {
    
        private Object target;             // 目标对象
    
        private AdviceBefore adviceBefore; // 前置通知
    
        private AdviceAfter adviceAfter;   // 后置通知
    
        // 生成代理对象核心方法
        public Object getProxyInstance() {
    
            Enhancer enhancer = new Enhancer();
            
            enhancer.setSuperclass(target.getClass());
            
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                    adviceBefore.before();
                    Object result = method.invoke(target, args);
                    adviceAfter.after();
                    return result;
                }
            });
            Object proxy = enhancer.create();
            return proxy;            // 返回代理对象
        }
    
        public AdviceBefore getAdviceBefore() {
            return adviceBefore;
        }
    
        public void setAdviceBefore(AdviceBefore adviceBefore) {
            this.adviceBefore = adviceBefore;
        }
    
        public AdviceAfter getAdviceAfter() {
            return adviceAfter;
        }
    
        public void setAdviceAfter(AdviceAfter adviceAfter) {
            this.adviceAfter = adviceAfter;
        }
    
        public Object getTarget() {
            return target;
        }
    
        public void setTarget(Object target) {
            this.target = target;
        }
    
    }

    测试类

    package cn.edu.cglibProxy;
    
    import org.junit.Test;
    
    public class ProxyTest {
    
        @Test
        public void fun() {
            
            Waiter waiter = new WaiterImpl();
            
            AdviceBefore before = new AdviceBefore() {             //生成前置通知
                @Override
                public void before() {
                    System.out.println("欢迎光临!");
                }
            };
            
            AdviceAfter after = new AdviceAfter() {
                @Override
                public void after() {
                    System.out.println("谢谢光临!");                //生成后置通知
                }
            };
            
            ProxyFactory proxyFactory = new ProxyFactory();        //生成工厂
            
            proxyFactory.setTarget(waiter);                          //设置目标对象
            proxyFactory.setAdviceBefore(before);                    //设置前置通知
            proxyFactory.setAdviceAfter(after);                      //设置后置通知
            
            Waiter proxy = (Waiter)proxyFactory.getProxyInstance();  //获得代理对象
            
            proxy.server();                                          //调用目标对象的方法
        }
        
    }

    测试结果

     

    四、总结  

      通过上面的两个例子,可以体会到动态代理的优势。静态代理是由程序员手动编写好源代码,在程序运行时已经存在了class文件,而动态代理则是在运行时根据需要动态生成的,不仅减少了工作量,使用时也更加灵活。

    转载于:https://www.cnblogs.com/wanghang-learning/p/9160557.html

    展开全文
  • JDK动态代理 此时代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑。 代理模式在实际使用时需要指定具体的目标对象,...

     

    JDK动态代理

    此时代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑。

    代理模式在实际使用时需要指定具体的目标对象,如果为每个类都添加一个代理类的话,会导致类很多,同时如果不知道具体类的话,怎样实现代理模式呢?这就引出动态代理。

    JDK动态代理只能针对实现了接口的类生成代理。

     

    CGLIB代理

    CGLIB(CODE GENERLIZE LIBRARY)代理是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的所有方法,所以该类或方法不能声明称final的。

    如果目标对象没有实现接口,则默认会采用CGLIB代理;

    如果目标对象实现了接口,可以强制使用CGLIB实现代理(添加CGLIB库,并在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)。

     

    转载于:https://www.cnblogs.com/hwaggLee/p/4501918.html

    展开全文
  • 1.JDK动态代理当一个对象(客户端)不能或者不想直接引用另一个对象(目标对象),这时可以应用代理模式在这两者之间构建一个桥梁--代理对象,此代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个...
    当一个对象(客户端)不能或者不想直接引用另一个对象(目标对象),这时可以应用代理模式在这两者之间构建一个桥梁--代理对象。按照代理对象的创建时期不同,可以分为两种:
    静态代理:程序员事先写好代理对象类,在程序发布前就已经存在了;
    动态代理:应用程序发布后,通过动态创建代理对象。
    其中动态代理又可分为:

    1.JDK动态代理

    此时代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑。

    代理模式在实际使用时需要指定具体的目标对象,如果为每个类都添加一个代理类的话,会导致类很多,同时如果不知道具体类的话,怎样实现代理模式呢?这就引出动态代理。

     

    JDK动态代理只能针对实现了接口的类生成代理。

     

    2.CGLIB代理

    CGLIB(CODE GENERLIZE LIBRARY)代理是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的所有方法,所以该类或方法不能声明称final的。

     

    如果目标对象没有实现接口,则默认会采用CGLIB代理;

    如果目标对象实现了接口,可以强制使用CGLIB实现代理(添加CGLIB库,并在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)。

     

     

    AOP包括切面(aspect)、通知(advice)、连接点(joinpoint),实现方式就是通过对目标对象的代理在连接点前后加入通知,完成统一的切面操作。
    展开全文
  • CGLib动态代理

    2016-10-29 14:43:00
    使用JDK创建代理有一个限制,即它要求被代理对象实现了某一个或某些接口,如果被代理对象没有实现接口,可以使用CGLib实现动态代理~ CGLib采用底层的字节码技术,可以为一个类创建子类,在子类中采用方法拦截的技术...
  • cglib动态代理

    2016-10-22 23:01:00
    代理即为访问对象添加一层控制层,使其间接化,控制层可以为对象访问添加操作属性。...区别于JDK动态代理,cglib不需要实现接口。 实例: 1 import java.lang.reflect.Method; 2 3...
  • 优点:特别添加了对属性的的操作。。缺点:不支持使用魔法方法。# coding=utf-8class NativeProxy(object):def __init__(self, target):object.__setattr__(self, "_target", target)def __getattribute__(self, ...
  • castle动态代理的使用

    2018-01-26 16:49:00
    转自:https://blog.csdn.net/educast/article/details/6565447#动态代理的原理 ...通过对T中方法或属性等,添加些自定义的操作,从而实现对原对象访问的封装. 动态代理实现(利用castle) castle的...
  • 1、动态代理:为目标对象创建一个代理类,该代理类拥有目标对象的方法,属性,同时也可添加自己的方法,比如:日志的添加、校验等。 2、实现条件:在java中规定,要想产生一个对象的代理对象,那么这个对象必须要有...
  • 1.JDK动态代理此时代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑。代理模式在实际使用时需要指定具体的目标对象,...
  • 在业务中使用动态代理,一般是为了给需要实现的方法添加预处理或者添加后续操作,但是不干预实现类的正常业务,把一些基本业务和主要的业务逻辑分离。我们一般所熟知的Spring的AOP原理就是基于动态代理实现的。 动态...
  • (3)使用mapper动态代理

    2020-05-10 20:42:01
    使用mapper动态代理 在之前的代码中,我们实现了一个工具类用于获取SqlSession,然后实现了一个dao接口的实现类,在这个实现类中通过...1、在StudentMapper.xml中的mapper标签中添加namespace属性: <mapper namesp
  • Javassist是一个开源的分析、编辑和创建Java字节码的类库,JAVASSIST可以动态修改类,比如添加方法和属性。JAVASSIST的目标类也没有接口限制。 动态代理常用在RPC接口调用中,因此选择一个好的动...
  • 动态代理&多表关联

    2020-04-22 08:25:06
    2.if:用于进行条件判断,test属性,用于指定判断条件.在sql语句后强行添加where 1=1 的恒成立; 3.where标签:如果没有条件, 不会生成 where 关键字;如果有条件, 会自动添加 where 关键字;如果第一个条件中有 and, ...
  • 为什么要采用代理模式呢?代理模式有什么用处与功能? 对于创建的一个类,我们在使用这个类...代理类需要将委托类包含进来,作为自己的一个属性成员,以便在代理类中通过这个属性成员调用委托类的方法。注意,代理类是
  • 1.JDK动态代理 此时代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑。 代理模式在实际使用时需要指定具体的目标...
  • 代理是在模型添加数据后创建的,但不是立即创建,如此在线程忙碌时添加数据代理不会马上生成,而是在空闲时生成,如此要调用代理项需保证它已生成。 代理初始化时一致的,如需特殊化,需要手动修改各个属性。 代码...
  • 一、使用Mapper动态代理的要求:1)session.getMapper()中的参数为所要代理的接口类型2)映射文件的namespace属性值为所要代理的接口的全限定性类名3)映射文件中的statement的id名称必须要与接口中相应方法的名称...
  • 代理是在运行时动态生成的,因此您无需更改模型类即可开始拦截其属性或方法。 顺便说一下,在模型类中包含方法和任何其他逻辑不是一个好的设计决定。 让我首先定义一个用户故事。 用户故事3:拦截模型调用 添加...

空空如也

空空如也

1 2 3 4 5 ... 12
收藏数 240
精华内容 96
关键字:

动态代理添加属性