设计模式之代理模式
代理模式
代理模式是常用的java设计模式,他的特征是代理类与委托类具有相同的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类对象的相关方法,来提供特定的服务;
静态代理类实例代码:
public interface Subject { void operation(); }
public class RealSubject implements Subject { @Override public void operation() { System.out.println("real subject operate started......"); } }
public class Proxy implements Subject { //对象的组合可以在运行时动态改变行为 private Subject subject; public Proxy(Subject subject) { this.subject = subject; } @Override public void operation() { System.out.println("before operate......"); subject.operation(); System.out.println("after operate......"); } }
public class Client { public static void main(String[] args) { Subject subject = new RealSubject(); Proxy proxy = new Proxy(subject); proxy.operation(); } }
动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码,动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java反射机制可以生成任意类型的动态代理类。java.lang.reflect包中的Proxy类和InvocationHandler接口提供了生成动态代理类的能力
动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体时实,代理一般会实现它所表示的实际对象的接口,代理可以访问实际对象,但是延迟实现实际对象的部分功能,时间对象实现系统的实际功能,代理对象对客户隐藏了实际对象,客户端不知道 它是与代理打交道还是与实际对象打交道
好处:可以对请求进行任何处理,在不允许直接访问某些类的情况下对访问要做做特殊处理等
1.JDK动态代理:利用java反射机制实现,必须有对应的接口
JDK动态代理中包含一个类和一个接口
1.1 InvocationHandler接口:
public interface InvocationHandler { // proxy:在其上调用方法的代理实例,method:要调用的方法;args:方法调用所需要的参数 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
1.2 Proxy类:
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法
public static Object newProxyInstance(ClassLoader loader, Class<?>[] inter faces, InvocationHandler h)
loader:类加载器
interfaces:类全部的接口
h:得到InvocationHandler接口的子类实现
实例部分:
public interface StudentDAO { //保存学生 void saveStudent(Integer i); //查询学生 void query(); }
public class StudentDAOImpl implements StudentDAO { @Override public void saveStudent(Integer i) { System.out.println("save student material..."+i.toString()); } @Override public void query() { System.out.println("query student info"); } }
public class StudentDAOProxy implements InvocationHandler { private Object orginalObject; public Object bind(Object obj){ this.orginalObject = obj; return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this); } private void preMethod(){ System.out.println("------------方法执行之前--------------"); } private void afterMethod(){ System.out.println("------------方法执行之后--------------"); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result ; preMethod(); result = method.invoke(this.orginalObject,args); afterMethod(); return result; } }
public class TestStudentDAOTest { public static void main(String[] args){ StudentDAO dao = new StudentDAOImpl(); StudentDAOProxy proxy = new StudentDAOProxy(); dao = (StudentDAO)proxy.bind(dao); dao.saveStudent(12); dao.query(); } }
JDK的动态代理依靠接口实现,如果有些类并没有接口,则不能使用JDK代理,这就要使用Cglib动态代理了
2.Cglib动态代理:不依赖接口
CGLIB包的底层是通过使用一个小而快的字节码处理矿建ASM,来转换字节码并生成新的类,除了CGLIB包,脚本语言例如Groovy和BeanShell也是使用ASM来生成字节码,不推荐直接使用ASM,因为它要求对JVM内部结构包括class文件的格式和指令集都很熟悉 ;CGlib是一个强大的高性能的代码生成包,被许多AOP框架使用,如Spring AOP,为他们提供方法的interception拦截
public interface MethodInterceptor extends Callback { Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable; }
- obj:代理对象
- method:拦截方法
- args:方法参数
- proxy:拦截器
实例:
public abstract class AbstractStudentDAO { public abstract void saveStudent(); public abstract void queryStudent(); }
public class CglibProxy implements MethodInterceptor { private Object originalObj; public Object bind(Object obj){ this.originalObj = obj; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(obj.getClass()); enhancer.setCallback(this); return enhancer.create(); } private void preMethod(){ System.out.println("------------方法执行之前--------------"); } private void afterMethod(){ System.out.println("------------方法执行之后--------------"); } @Override public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { preMethod(); methodProxy.invokeSuper(obj,objects); afterMethod(); return null; } }
public class TestStudentDAOTest { public static void main(String[] args){ StudentDAO dao = new StudentDAOImpl(); StudentDAOProxy proxy = new StudentDAOProxy(); dao = (StudentDAO)proxy.bind(dao); dao.saveStudent(12); dao.query(); } }
spring缺省是支持Proxy动态代理,如何强制使用CGLIB生成代理
<aop:aspectj-autoproxy proxy-target-class=“true”/>
Transaction:
<tx: annotation-driven transaction-manager=“teManager” proxy-target-class=“true” />
AOP(Aspect Oriented Programming)它是一种设计模式,用于实现一个系统中的应用
- 日志拦截
- 授权认证
- 事务拦截
- 方法缓存
- 数据审计
- Aspect(切面):指横切性关注点的抽象即为切面,它与类相似,只是两者的关注点不一样,类是对物体特征的抽象,而切面横切性关注点的抽象
- JoinPoint(连接点):所谓连接点是指那些被拦截到的点,在Spring中,这些点指的是方法,因为spring只是支持方法类型的连接点,实际上joinpoint还可以是field或类构造器
- PointCut切入点:所谓切入点是指我们要对那些Joinpoint进行拦截的定义
- Advice(通知):所谓通知是指拦截到joinpoint之后所要做的事情就是通知,通知分为前置通知、后置通知、异常通知、最终通知、环绕通知
- Target(目标对象):代理的目标对象
- Weave(织入):指将aspects应用到target对象并导致Proxy对象创建的过程称为ahi入
- Introduction(引入):在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或Field
2.1 基于代理的AOP
- 创建bean
<bean id=“studentDaoImpl” class=“com.student.impl.StudentDaoImpl”/>
- 定义切入点
<bean id=“studentDaoPointCut” class=“org.springframework.aop.support.Jdk RegexMethodPointcut”> <property name=“pattern” value=“.*dao”> //指定正则表达式,匹配以dao结尾的方法 </bean>
- 定义通知
<bean id=“studentDaoAdvisor” class=“org.springframework.aop.support.DefaultPointcutAdvisor”> <property name=“advice” ref=“studentdDaoProxy”/> <property name=“pointcut” ret=“studentDaoPointCut”/> <bean>
- 定义代理工厂
<bean id=“studnetProxyFactory” class=“org.springframework.aop.framework. ProxyFactoryBean”> <property name=“interceptorNames” value=“studentDaoAdvisor”/> <property name=“proxyInterfaces” value=“com.student.StudentDAO”/> <bean>
- 测试
ApplicationContext ctx = new ClassPathXmlApplicationContext(“application.xml"); StudentDao dao = (StudnetDao) ctx.getBean(“studentProxyFactory); dao.saveStudent();
2.2 基于CGLIB的AOP
proxy动态代理只能对实现了接口的类生成代理,而不能针对类,CGLIB是针对类生成代理,主要是对用户类生成一个子类
基于代理的AOP实现过程比较复杂,可使用Spring提供的自动代理,让切入点和通知自动匹配
<bean id=“studentDaoAdvice” class=“org.springframework.aop.support.RegexdMet hodePointcutAdvisor”> <property name=“advice” ref=“studentDaoProxy”/> <property name=“pattern” value=“.*student”/> </bean> //声明使用自动代理 <bean class=“org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator”/>
2.3基于AspectJ 的AOP
<context:annotation-config/> <context:component-scan base-package=“com.student”/> <aop:aspectj-autoproxy/>
@Aspect //声明为切面 @Component //声明为组件 public class StudentAspectJProxy{ @Before(“execution(public void com.student.StudentDao.*student())") public void beforeMethod(){ System.out.println(“方法执行之前....."); } @Before(“execution(public void com.student.StudentDao.*student())") public void afterMethod(){ System.out.println(“方法执行之前....."); } }
public class StudentAspectJProxy{ @PointCut(“execution(public void com.student.StudentDao.*student())") public void doFilter(){ } @Before(“doFilter()") public void beforeMethod(){ System.out.println(“方法执行之前....."); } @AfterReturning(“doFilter()") public void afterMethod(){ System.out.println(“方法执行之前....."); } }
相关推荐
**设计模式之代理模式(Proxy Pattern)** 设计模式是软件工程中的一种最佳实践,它是在特定情境下解决常见问题的模板。代理模式是其中一种行为设计模式,它的核心思想是为一个对象提供一个替身或者代理,以控制对...
根据提供的标题“深入浅出设计模式之代理模式”与描述“将《Head First 设计模式》(中文版)按章节进行了分割,每章一个文件,方便大家下载”,我们可以推测出这部分内容主要聚焦于介绍和解释代理模式这一重要的设计...
代理模式是一种在软件设计中广泛使用的行为设计模式,它的核心思想是为...通过观看"设计模式之代理模式视频教学",你可以系统地学习代理模式的理论知识和实践技巧,提升自己的设计能力,更好地应对复杂的软件开发挑战。
大话设计模式之代理模式 经典代码 C#类
Java设计模式之代理模式 1.代理模式 1.1 静态代理 1.2 动态代理 1.3.代理模式使用原因和应用方面
代理模式是一种常用的设计模式,它在软件工程中扮演着重要的角色,特别是在.NET框架下。代理模式的核心思想是为一个对象提供一个替代品或代表,这个替代品能够控制对原对象的访问,使得客户端代码可以通过代理对象与...
### Java设计模式之虚拟代理模式详解 #### 一、引言 在软件工程领域,设计模式作为一种被广泛接受的最佳实践,对于提高代码质量和可维护性起着至关重要的作用。其中,“代理模式”作为结构型设计模式之一,在解决...
代理模式是一种常用的设计模式,它在软件开发中起到了中介或者代表的作用。代理模式的主要目的是为其他对象提供一种代理以控制对这个对象的访问。通过引入代理,我们可以增加新的功能,如缓存、日志记录、访问控制等...
代理模式是设计模式的一种,它提供了一种对目标对象进行增强或者控制访问的方式。在本实例中,我们将深入探讨Java中的代理模式及其应用。 代理模式的核心思想是为一个对象创建一个代理对象,这个代理对象在客户端和...
代理模式是面向对象设计模式中的一个关键概念,它在软件工程中扮演着重要角色,用于在客户端和目标对象之间创建一种代理关系,以提供额外的功能或控制。在代理模式中,代理类作为真实对象的代表,它可以在客户端与...
代理模式是设计模式中的一种结构型模式,它在对象交互中起到了中介的作用,允许通过代理对象来控制对原对象的访问。代理模式的核心思想是为一个对象提供一个替身,以便增加新的功能或者控制对原对象的访问。这种模式...
Java设计模式之代理模式[收集].pdf