Spring的IOC和AOP之深剖(7)

还有一个有趣的作用是可以用作远程调用,比如现在有Java接口,这个接口的实现部署在其它服务器上,在编写客户端代码的时候,没办法直接调用接口方法,因为接口是不能直接生成对象的,这个时候就可以考虑代理模式(动态代理)了,通过Proxy.newProxyInstance代理一个该接口对应的InvocationHandler对象,然后在InvocationHandler的invoke方法内封装通讯细节就可以了。具体的应用,最经典的当然是Java标准库的RMI,其它比如hessian,各种webservice框架中的远程调用,大致都是这么实现的。

动态代理我们分之为jdk动态代理和cglib动态代理

JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了。CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。

CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。

1.JDK动态代理

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

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

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

看看代码:

dao实现类

public class UserDaoImpl implements UserDao {

public void add() {
        System.out.println("add success");
    }
   
   
}

public class ProxySubject implements Subject {
 private Subject realSubject;
    public String request() {
        System.out.println("代理增强");
        return realSubject.request();
    }
    public Subject getRealSubject() {
        return realSubject;
    }
    public void setRealSubject(Subject realSubject) {
        this.realSubject = realSubject;
    }

public class RealSubject implements Subject {

public String request() {
        // TODO Auto-generated method stub
        return "真实主题";
    }

}

*/
public interface Subject {
public String request();
}

test

public static void main(String[] args) {
    /**
    * 静态代理
    */
        /*Subject sub=new RealSubject();//被代理对象
        System.out.println(sub.toString());
        ProxySubject ps=new ProxySubject();//代理对象
        System.out.println(ps.toString());
        ps.setRealSubject(sub);
        String request = ps.request();//走真实代理对象  RealSubject
        System.out.println(request);*/
       
        /**
        * 动态代理
        */
    final UserDao dao=new UserDaoImpl();
    //代理对象
    //第一个参数:获取和dao一样的类加载器,通过反射机制获取类加载器
    //new InvocationHandler()叫匿名内部类,拿到了接口的实现类
    UserDao newProxyInstance = (UserDao) Proxy.newProxyInstance(dao.getClass().getClassLoader(), dao.getClass().getInterfaces(), new InvocationHandler() {
        //newProxyInstance 被代理对象
        public Object invoke(Object newProxyInstance, Method method, Object[] args)
                throws Throwable {
            System.out.println("增强");
            //原始对象  dao    真正的dao   
            Object invoke = method.invoke(dao, args);
            System.out.println("记录日志");
            return invoke;
        }
       
    });
    //增强代理对象,方法
    newProxyInstance.add();
    }

applicationContext.xml

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/d0a66771283e2103c6bdc01c098f5a37.html