Spring 7:Proxy代理对象

※ 代理模式


    代理模式的特征是代理类与委托类有同样的接口(一般情况下)

    代理类主要负责给委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等

    代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联
    
    代理类的对象本身并不真正实现功能,而是通过调用委托类的对象的相关方法,来提供特定的功能

    注意:
        委托类对象就是我们后面说到的"目标对象", 也就是需要【被】代理的对象 target
        代理类对象就是我们后面说到的"代理对象",目标对象就是需要这个对象为其做为代理 proxy

    
    按照代理类的创建时期,代理类可分为两种。
        静态代理类:
            在程序运行前,代理类的.class文件就已经存在了
        动态代理类:
            在程序运行时,代理类是运用了反射技术或字节码技术动态创建而成的
※ 静态代理
   

 例如:
    接口:    HelloService
    委托类:    HelloServiceImpl
    代理类:    HelloServiceProxy

    public interface HelloService{
        public String sayHello(String msg);
    }

    public class HelloServiceImpl implements HelloService{
        public String sayHello(String msg){
            return "hi!"+msg;
        }
    }

    public class HelloServiceProxy implements HelloService{
        //目标对象
        private HelloService target;

        //构造器中接收目标对象
        public HelloServiceProxy(HelloService target){
            this.target=target;
        }

        public String sayHello(String msg){
            System.out.println("目标方法调用前");

            //调用目标对象的方法
            //这个方法才是我们真正要执行的方法
            String result = target.sayHello(msg);
            
            System.out.println("目标方法调用后");

            return result;
        }
        
    }
    
    main:
        HelloService target =
            new HelloServiceImpl();

        HelloService proxy =
            new HelloServiceProxy(target);
        
        System.out.println(proxy.sayHello("hello"));
测试例:
1.构建接口BookService实现类BookService

package com.briup.pojo;

public interface BookService {
	void saveBook(long id,String name);
	String get(long id);
	void list();
	void setTest();
}



package com.briup.pojo;

public class BookServiceImpl
	implements BookService{
	@Override
	public void saveBook(long id, String name) {
		// TODO Auto-generated method stub
		System.out.println("saveBook....");
	}

	@Override
	public String get(long id) {
		// TODO Auto-generated method stub
		System.out.println("get....");
		return "test...ok";
	}

	@Override
	public void list() {
		// TODO Auto-generated method stub
		System.out.println("list....");
	}

	@Override
	public void setTest() {
		// TODO Auto-generated method stub
		System.out.println("set.....");
	}

}


2.静态代理类:

package com.briup.aop.proxy.staticProxy;

import com.briup.pojo.BookService;
import com.briup.pojo.BookServiceImpl;

public class BookServiceproxy 
	implements BookService{
	private BookServiceImpl bs;
	@Override
	public void saveBook(long id, String name) {
		// TODO Auto-generated method stub
		System.out.println("before....");
		bs.saveBook(id, name);
		System.out.println("after....");
	}

	@Override
	public String get(long id) {
		// TODO Auto-generated method stub
		System.out.println("before....");
		String str=bs.get(id);
		System.out.println("after....");
		return str;
	}

	@Override
	public void list() {
		// TODO Auto-generated method stub
		System.out.println("before....");
		bs.list();
		System.out.println("after....");
	}

	public BookServiceImpl getBs() {
		return bs;
	}

	public void setBs(BookServiceImpl bs) {
		this.bs = bs;
	}

	@Override
	public void setTest() {
		// TODO Auto-generated method stub
		
	}

}



3.配置文件xml:

<?xml version="1.0" encoding="UTF-8"?>
  <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd"
          >
          <bean name="target" 
          class="com.briup.pojo.BookServiceImpl">
          </bean>
          <bean name="service" 
          class="com.briup.aop.proxy.staticProxy.BookServiceproxy">
          	<property name="bs" ref="target"></property>
          </bean>
</beans>



4.测试类:
package com.briup.aop.proxy.staticProxy;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.briup.pojo.BookService;

public class StaticProxyTest {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext cp=
				new ClassPathXmlApplicationContext(
						"com/briup/aop/proxy/staticProxy/staticProxy.xml");
		BookService bs=
				(BookService) cp.getBean("service");
		bs.saveBook(1, "tom");
		bs.get(1);
		bs.list();
	}
}


※ 动态代理
    动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。
    
    动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为使用它可以生成任意类型的动态代理类
    
    java.lang.reflect包下面的
        Proxy类和InvocationHandler接口
    提供了生成动态代理类的能力
    
  

 例子:
    接口:
    public interface IStudentService {
    
        void save(Student s);
        
        void delete(long id);
        
        Student find(long id);
    
    }
   
    实现类
    public class StudentServiceImpl implements IStudentService {
        public void delete(long id) {
            // 记录日志
            System.out.println("student is deleted...");
        }

        public Student find(long id) {
            // 记录日志
            System.out.println("student is found...");
            return null;
        }

        public void save(Student s) {
            // 记录日志
            System.out.println("student is saved...");
        }
    }

    日志类:
    public class StudentLogger {
        public void log(String msg){
            System.out.println("log: "+msg);
        }
    }
   
    //InvocationHandler接口的实现类,java的动态代理中需要使用
    public class MyHandler implements InvocationHandler {
        //目标对象
        private Object target;
        private StudentLogger logger = new StudentLogger();

        public MyHandler() {
        }

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

        // 参数1 将来所产生的代理对象 Proxy4$
        // 参数2 将来需要调用到的目标对象里面真正的那个方法的镜像
        // 参数3 将来调用方法的时候所传的参数
        public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
            // 获得将来所调用方法的名字
            String methodName = m.getName();
            // 用日志记录输出一下
            logger.log(methodName + " is invoked...");
            // 用反射的方式去调用将来需要真正调用的方法.
            Object o = m.invoke(target, args);

            return o;
        }
        get/set
        ....
    }

    main:
        //目标对象
        IStudentService service = new StudentServiceImpl();
        
        //service是我们的目标对象
        //我们要给目标对象产生代理对象
        //目标对象service只能单独执行delete方法。
        //但是我们需要的是:先执行log日志方法再执行delete方法
        //目标对象service做不到这个要求,所以我们要给目标对象service生成一个代理对象去完成这俩个操作


        /*JDK动态代理的方式获得代理对象*/

        //获得目标对象的Class对象
        Class c = service.getClass();

        //获得目标对象的类加载器对象
        ClassLoader classLoader = c.getClassLoader();

        //获得目标对象所实现的所有接口
        Class[] interfaces = c.getInterfaces();

        //获得一个InvocationHandler接口的实现类对象,并把目标对象传进去
        InvocationHandler h =
                new MyHandler(service);

        //参数1 目标对象的类加载器对象
        //参数2 目标对象所实现的所有接口. Class类型数组
        //参数3 InvocationHandler接口的实现类对象
        IStudentService proxy =
            (IStudentService)Proxy.newProxyInstance
            (classLoader, interfaces, h);
        //这里的proxy是一个实现了IStudentService接口动态生成的代理类的对象
        proxy.delete();
JDK动态代理方式:
1.BookService接口和BookServiceImpl实现类同上

package com.briup.pojo;

public interface BookService {
	void saveBook(long id,String name);
	String get(long id);
	void list();
	void setTest();
}



package com.briup.pojo;

public class BookServiceImpl
	implements BookService{
	@Override
	public void saveBook(long id, String name) {
		// TODO Auto-generated method stub
		System.out.println("saveBook....");
	}

	@Override
	public String get(long id) {
		// TODO Auto-generated method stub
		System.out.println("get....");
		return "test...ok";
	}

	@Override
	public void list() {
		// TODO Auto-generated method stub
		System.out.println("list....");
	}

	@Override
	public void setTest() {
		// TODO Auto-generated method stub
		System.out.println("set.....");
	}

}


2.先写测试类,目前先不将代理类构建对象写在xml文件内,以便分析(注释部分)

package com.briup.aop.proxy.jdkproxy;

import java.lang.reflect.Proxy;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.briup.pojo.BookService;
import com.briup.pojo.BookServiceImpl;

public class JdkProxyTest {
	public static void main(String[] args) {
		//目标对象的构建
//		BookService bs=
//				new BookServiceImpl();
//		//处理器的构建
//		MyHandler handler=
//				new MyHandler();
//		//给处理器设置目标对象
//		handler.setTarget(bs);
		/*
                 *Proxy类 jdk提供的代理类
		 * 前提:目标对象必须实现接口
		 * 第一个参数表示类加载器
		 * 第二个参数目标对象的所有接口
		 * Class[] interfaces
		 * 第三个参数处理器器(对切面
		 * 所包含的所有方法生效)
		 */
//		BookService proxy=
//				(BookService) Proxy.newProxyInstance(
//				bs.getClass().getClassLoader()
//				, bs.getClass().getInterfaces(),
//				handler);
//		//proxy.saveBook(1, "tom");
//		String name=proxy.get(1);
//		System.out.println(name+"---");
//		proxy.list();
		ClassPathXmlApplicationContext cp=
				new ClassPathXmlApplicationContext(
						"com/briup/aop/proxy/jdkproxy/jdkProxy.xml");
		BookService bs=
				(BookService) cp.getBean("proxy");
		//bs.saveBook(1, "tom");
		bs.setTest();
	}
}



3.构建代理类对象中的handler

package com.briup.aop.proxy.jdkproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;

import com.briup.pojo.BookService;
import com.briup.pojo.BookServiceImpl;

/*
 * 方法的处理器(针对整个切面)
 */
public class MyHandler 
	implements InvocationHandler{
	//目标对象
	private Object target;

	/*
	 * 第一个参数代理对象
	 * 第二参数方法目标对象的镜像
	 * 第三参数表示目标对象中方法的参数
	 * 
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//		System.out.println(method.getName()+"&&");
//		System.out.println(Arrays.toString(args)+"&&");
		System.out.println("before....");
		//调用该镜像所对应的方法
		//第一个参数目标对象的实列
		Object obj=method.invoke(target, args);
//		System.out.println("return :"+obj);
		System.out.println("after....");
		return obj;
	}

	public Object getTarget() {
		return target;
	}

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

}


4.由于xml文件构建对象不能通过java已给类方法构建bean标签
所以利用spring工厂构建工厂类

package com.briup.aop.proxy.jdkproxy;

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

import org.springframework.beans.factory.FactoryBean;

public class jdkFactory 
	implements FactoryBean<Object>{
	private Object target;//目标对象
	private Class[] interfaces;//目标对象实现的所有接口
	private InvocationHandler handler;//处理器
	@Override
	public Object getObject() throws Exception {
		Object proxy=
		Proxy
		.newProxyInstance(target.getClass().getClassLoader()
				, interfaces, handler);
		return proxy;
	}

	@Override
	public Class<?> getObjectType() {
		// TODO Auto-generated method stub
		return null;
	}

	public Object getTarget() {
		return target;
	}

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

	public Class[] getInterfaces() {
		return interfaces;
	}

	public void setInterfaces(Class[] interfaces) {
		this.interfaces = interfaces;
	}

	public InvocationHandler getHandler() {
		return handler;
	}

	public void setHandler(InvocationHandler handler) {
		this.handler = handler;
	}

}



5.将测试类中代理类对象的生成写在xml配置文件内


<?xml version="1.0" encoding="UTF-8"?>
  <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd"
          >
          <!-- 目标对象的配置 -->
    <bean name="target" 
    class="com.briup.pojo.BookServiceImpl"></bean>
    <!-- 配置处理器 -->
    <bean name="handler" 
    class="com.briup.aop.proxy.jdkproxy.MyHandler">
    	<property name="target" ref="target"></property>
    </bean>
    <bean name="proxy" 
    	class="com.briup.aop.proxy.jdkproxy.jdkFactory">
   	<property name="target" ref="target"></property> 	
   	<property name="interfaces">
   		<array>
   			<value>com.briup.pojo.BookService</value>
   		</array>
   	</property> 	
   	<property name="handler" ref="handler"></property> 	
   </bean>
</beans>

※ CGLib代理
    JDK动态代理要求目标类实现接口,才能对其进行代理
    
    对于没有实现接口的类,可以使用CGLib进行动态代理
    
    CGLib采用了非常底层的字节码技术(依靠ASM的jar包,开一种开源的java字节码编辑类库),其原理是通过字节码技术为目标类创建一个子类对象,并在子类对象中拦截所有父类方法的调用,然后在方法调用前后调用后都可以加入自己想要执行的代码
    
    注:高版本的spring中,已经在spring-core-xx.jar中,把cglib和asm的核心代码整合了进来
    cglib代理的例子:
  

  //目标类,没有实现任何接口
    //通过字节码技术创建这个类的子类,实现动态代理
    //这时,目标类作为父类,代理对象就是根据目标类动态生成的子类对象
    public class SayHello{
        public void say(){
            System.out.println("hello");
        }
    }

    public class CglibProxy implements MethodInterceptor{
        
        //创建出一个指定父类型的子类对象
        public Object getProxy(Class c){
            Enhancer enhancer = new Enhancer();
            //设置谁是父类
            enhancer.setSuperclass(c);
            enhancer.setCallback(this);
            //通过字节码技术动态创建子类实例
            return enhancer.create();
        }

        //intercept方法会拦截所有代理对象中方法的调用
        //obj   参数:将来生成的代理对象
        //method参数:将来代理对象所调用的方法的镜像
        //args  参数:将来代理对象调用方法时所传的参数
        //mproxy参数:该参数可以用来调用到父类中的方法
        public Object intercept(Object obj, Method method, Object[] args,MethodProxy mproxy) throws Throwable {
            System.out.println("目标方法执行之前");
            
            //调用父类中的方法
            Object result = mproxy.invokeSuper(obj, args);

            System.out.println("目标方法执行之后");
            return result;
        }
    }


    main:
        CglibProxy proxy = new CglibProxy();
        //通过生成子类的方式创建代理类
        SayHello s = (SayHello)proxy.getProxy(SayHello.class);
        s.say();

    输出结果:
    目标方法执行之前
    hello
    目标方法执行之后
例:
cglib一般用于没有接口的实体类
1.实体类

package com.briup.pojo;

public class ProductService {
 public void saveProduct(long id,String name) {
	 System.out.println("saveProduct...");
 }
 public int getProduct() {
	 System.out.println("getProduct...");
	 return 33;
 }
}



2.构建代理类

package com.briup.AOP.proxy.cglibproxy;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

/*
 * cglib构建代理对象
 * 解决了没有接口的目标对象
 * 如何在方法之前和之后做操作
 * (有接口也可以用)
 */
public class CglibproxyTest implements MethodInterceptor{
	private Object target;
	
	public Object getTarget() {
		return target;
	}
	public void setTarget(Object target) {
		this.target = target;
	}
	/*
	 * 自定义方法构建代理对象
	 * 方法如果传参数,参数是目标对象的镜像
	 */
	public Object getProxy() {
		Enhancer en=new Enhancer();
		//把目标对象设置成父类
		en.setSuperclass(target.getClass());
		//回调函数:代理调用目标对象方法的时候执行当前类intercept方法
		en.setCallback(this);
	    return en.create();
		
	}
   /*
    * 当代理对象执行和目标对象相同方法的时候直接进行intercept
    * 第一个参数代理对象
    * 第二个参数目标对象方法的镜像
    * 第三个参数方法的参数
    * 第四个参数代理对象方法的镜像
    */
	@Override
	public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("before...");
		//Object obj=arg3.invoke(arg0, arg2);
		Object obj=arg1.invoke(target, arg2);
		System.out.println("after...");
		return obj;
	}

}



3.配置文件xml


<?xml version="1.0" encoding="UTF-8"?>
  <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd"
          >
<bean name="target" class="com.briup.pojo.ProductService"></bean>
<bean name="factory" class="com.briup.AOP.proxy.cglibproxy.CglibproxyTest">
<property name="target" ref="target"></property>
</bean>
<!--工厂方法调用产生对象  -->
<bean name="proxy" factory-bean="factory" factory-method="getProxy"></bean>
 </beans>


4.测试类

package com.briup.AOP.proxy.cglibproxy;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.briup.pojo.ProductService;

public class CglibTest {
public static void main(String[] args) {
//	CglibproxyTest cp=new CglibproxyTest();
//	ProductService ps=
//	(ProductService) cp.getProxy(ProductService.class);
//	ps.saveProduct(1, "jake");
//	ps.getProduct();
ClassPathXmlApplicationContext cp=
new ClassPathXmlApplicationContext("com/briup/AOP/proxy/cglibproxy/cglib.xml");
ProductService ps=(ProductService) cp.getBean("proxy");
ps.saveProduct(1, "tom");
ps.getProduct();
}
}

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值