代理模式主要有兩種:靜態代理和動態代理
代理模式 代理模式是常用的 Java 設計模式,它的特征是代理類與委托類有同樣的接口,代理類主要負責為委托類預處理消息、過濾消息、把消息轉發給委托類,以及事后處理消息等。代理類與委托類之間通常會存在關聯關系,一個代理類的對象與一個委托類的對象關聯, 代理 類的對象本身並不真正實現服務, 而是通過調用委托類的對象的相關方法, 來提供特定的服務. 按照代理類的創建時期,代理類可分為兩種。
1.靜態代理類: 由程序員創建或由特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類 的.class 文件就已經存在了。
靜態代理類 如下:
StudentImpl 類是代理類,
public class StudentImpl implements IStudentServiceDAO { StudentServiceImpl service; StudentImpl(StudentServiceImpl service) { this.service = service; } @Override public void save(Student stu) { System.out.println("開啟事務"); service.save(stu); System.out.println("提交事務"); } }
StudentServiceImpl 類是委托類,
public class StudentServiceImpl implements IStudentServiceDAO { @Override public void save(Student stu) { System.out.println("調用dao層保存方法"); } }
這兩個類都實現了 HelloService 接口.
其中 StudentServiceImpl 類是 IStudentServiceDAO 接口的真正實現者,
而 StudentImpl 類是通過調用 StudentServiceImpl 類的相關方法來提供特定服務的.
StudentImpl 類的 save()方法會分別調用被代理的 StudentServiceImpl 對象的 save()方法,並且在方法調用前后都會執行一些簡單的打印操作。 由此可見,代理類可以為委托類預處理消息、把消息轉發給委托類和事后處理消息等。
測試類代碼:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration public class StaticProxyTest { @Autowired @Qualifier("servicetran") IStudentServiceDAO service; @Test public void testStaticProxy() { service.save(new Student("ZhangSan", 18)); } }
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">
<--id="service"的類為委托類---> <bean id="service" class="com.gxxy.spring_05proxy.static1.StudentServiceImpl"></bean>
<--id="servicetran"的類為代理類--> <bean id="servicetran" class="com.gxxy.spring_05proxy.static1.StudentImpl"> <constructor-arg name="service" ref="service"></constructor-arg> </bean> </beans>
類的源代碼是由程序員編寫的,在程序運行前,它的.class 文件就已經存在了,這種代理類稱為靜態代理類。
2.動態代理類:在程序運行時,運用反射機制動態創建而成。
動態代理類的字節碼在程序運行時由Java 反射機制動態生成,無需程序員手工編寫它的源代碼.動態代理類不僅簡化了編程工作,而且提高了 軟件系統的可擴展性,因為Java反射機制可以生成任意類型的動態代理類.
java.lang.reflect 包中的 Proxy 類和 InvocationHandler 接口提供了生成動態代理類的能力。
Proxy 類提供了創建動態代理類及其實例的靜態方法。
①:接口(interface)/InvocationHandler
代理類:實現 InvocationHandler 接口 注意: InvocationHandler 是 import java.lang.reflect.InvocationHandler包中的;
package com.gxxy.spring_05proxy.dynamic.interfaces; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class ProxyDynamicInvocationHandler implements InvocationHandler { private IStudentServiceDAO service; ProxyDynamicInvocationHandler(IStudentServiceDAO service) { this.service = service; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Begin"); System.out.println("save"); System.out.println("commit"); System.out.println("-------"+method.getName()); return method.invoke(service, args); } }
委托類:(實現IStudentServiceDAO 接口,接口中只有save()方法)
public class StudentServiceImpl implements IStudentServiceDAO { @Override public void save(Student stu) { System.out.println("調用dao層保存方法"); } }
測試類:
package com.gxxy.spring_05proxy.dynamic.interfaces; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration public class DynamicProxyTest { @Autowired IStudentServiceDAO service; @Test public void testStaticProxy() { ClassLoader loader = IStudentServiceDAO.class.getClassLoader(); Class<?>[] interfaces = new Class<?>[] { IStudentServiceDAO.class }; InvocationHandler h = new ProxyDynamicInvocationHandler(service); IStudentServiceDAO newProxyInstance = (IStudentServiceDAO) Proxy.newProxyInstance(loader, interfaces, h); newProxyInstance.save(new Student("ZhangSan",18)); } }
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 id="service" class="com.gxxy.spring_05proxy.dynamic.StudentServiceImpl"></bean> </beans>
②:繼承(inherit)/Enhancer
代理類:實現 InvocationHandler 接口 注意: InvocationHandler 是 import org.springframework.cglib.proxy.InvocationHandler 包中的;
package com.gxxy.spring_05proxy.dynamic.inherit; import java.lang.reflect.Method; import org.springframework.cglib.proxy.InvocationHandler; public class ProxyDynamicInvocationHandler implements InvocationHandler { private Object service; ProxyDynamicInvocationHandler(StudentServiceImpl service) { this.service = service; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Begin"); System.out.println("save"); System.out.println("commit"); System.out.println("-------" + method.getName()); return method.invoke(service, args); } }
委托類:StudentServiceImpl
package com.gxxy.spring_05proxy.dynamic.inherit; public class StudentServiceImpl { public void save(Student stu) { System.out.println("調用dao層保存方法"); } }
測試類:
package com.gxxy.spring_05proxy.dynamic.inherit; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.InvocationHandler; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration public class DynamicinheritProxyTest { @Autowired StudentServiceImpl service; @Test public void testStaticProxy() { ClassLoader loader = StudentServiceImpl.class.getClassLoader(); InvocationHandler handle = new ProxyDynamicInvocationHandler(service); Enhancer hancer = new Enhancer(); hancer.setClassLoader(loader); hancer.setSuperclass(StudentServiceImpl.class); hancer.setCallback(handle); StudentServiceImpl create = (StudentServiceImpl) hancer.create(); create.save(new Student("Jack", 18)); } }
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 id="service" class="com.gxxy.spring_05proxy.dynamic.inherit.StudentServiceImpl"></bean> </beans>