代理模式
代理模式是常用的java设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。
代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类对象的相关方法,来提供特定的服务。
代理分类
静态代理:由程序员创建或特定工具自动生成源代码。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。
静态代理代码示例
首先创建接口:
package org.iti.wxl.staticproxy;
/**
* 接口
*/
public interface UserService {
public void saveUser();
public void deleteUser();
}
对接口的实现:(这里就不连接数据库了,只做简单的实例)
package org.iti.wxl.staticproxy;
public class UserServiceImpl implements UserService {
@Override
public void saveUser() {
System.out.println("==user saved!==");
}
@Override
public void deleteUser() {
System.out.println("==user deleted!==");
}
}
代理类:
package org.iti.wxl.staticproxy;
public class UserServiceImplProxy implements UserService {
private UserServiceImpl userServiceImpl;
public UserServiceImplProxy(UserServiceImpl userServiceImpl) {
this.userServiceImpl = userServiceImpl;
}
@Override
public void saveUser() {
System.out.println("save begin!");
userServiceImpl.saveUser();
System.out.println("save end!");
}
@Override
public void deleteUser() {
System.out.println("delete begin!");
userServiceImpl.deleteUser();
System.out.println("delete end!");
}
}
代理类同样实现了UserService接口,代理类持有UserServiceImpl,并且重写了UserService接口里的方法,在方法里添加了逻辑。
测试方法:
package org.iti.wxl.staticproxy;
public class StaticProxy {
//静态代理方法测试
public static void main(String[] args) {
UserServiceImpl userServiceImpl = new UserServiceImpl();
UserServiceImplProxy userServiceImplProxy =
new UserServiceImplProxy(userServiceImpl);
userServiceImplProxy.saveUser();
System.out.println("=============");
userServiceImplProxy.deleteUser();
}
}
把创建的UserServiceImpl交给代理类UserServiceImplProxy,由它的实例执行数据逻辑操作。
方法运行结果如下:
save begin!
==user saved!==
save end!
=============
delete begin!
==user deleted!==
delete end!
代理类中添加的逻辑在方法运行时被执行了。
观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。
解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。
jdk动态代理
jdk动态代理中包含一个类和一个接口,用到了java的反射机制:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args);
}
参数说明:
Object proxy:代理类对象。
Method method:要调用的方法
Object[] args:方法调用时所需要的参数
下面用代码说明jdk动态代理的使用
接口类:
package org.iti.wxl.dynamicproxy;
public interface UserService {
public void addUser();
public void deleteUSer();
}
对接口的实现:
package org.iti.wxl.dynamicproxy;
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("==add user==");
}
@Override
public void deleteUSer() {
System.out.println("==delete user==");
}
}
代理类:
package org.iti.wxl.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class UserServiceImplProxy implements InvocationHandler {
private Object target;
public Object bind(Object target){
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
System.out.println("user add begin!");
result = method.invoke(target, args);
System.out.println("user add end!");
return result;
}
}
代理类主要负责两项功能:1、把Object转化成代理类的一个实现;2、为方法添加逻辑(如日志,性能测试等)。
测试类:
package org.iti.wxl.dynamicproxy;
public class DynamicProxy {
public static void main(String[] args) {
UserServiceImplProxy proxy = new UserServiceImplProxy();
UserService userServiceProxy = (UserService)proxy.
bind(new UserServiceImpl());
userServiceProxy.addUser();
System.out.println("========");
userServiceProxy.deleteUSer();
}
}
测试结果:
user add begin!
==add user==
user add end!
========
user add begin!
==delete user==
user add end!
分析:
可以将InvocationHandler接口的子类想象成一个代理的最终操作类。
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了操作方法: newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
参数说明:
ClassLoader loader:类加载器
Class<?>[] interfaces:全部的接口
InvocationHandler h:InvocationHandler接口的子类实例
在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器:
Booststrap ClassLoader:此加载器采用C++编写,一般开发中是看不到的。
Extendsion ClassLoader:用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类。
AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。
这三个类的继承关系是Extendsion ClassLoader继承Booststrap ClassLoader,AppClassLoader继承Booststrap ClassLoader,每加载一个类都现有父类加载,父类没有再用其孩子类加载,保证了安全性。另外我们也可以写自己的类加载器,为类加载器加密等。
动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
spring AOP
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。Spring主要通过代理来实现AOP。
切面(Aspect):对横切关注点的抽象(类似类对对象的抽象)
连接点(JoinPoint):被拦截到的点,泛指方法。
切入点(CutPoint):对哪些连接点进行拦截的定义。
通知(Advice):在特定的连接点,AOP框架执行的动作.前置/后置/例外/最终/环绕通知。
引入(Introduction): 添加方法或字段到被通知的类。Spring允许引入新的接口到任何被通知的对象。
目标对象(Target Object): 包含连接点的对象。也被称作被通知或被代理对象。
AOP代理(AOP Proxy): AOP框架创建的对象,包含通知。在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
织入(Weaving): 组装切面来创建一个被通知对象。这可以在编译时完成也可以在运行时完成。Spring在运行时完成织入。
示例代码:
接口类:
package org.iti.wxl.springaop;
public interface UserService {
public String getUser(String userId);
public void addUser();
}
对接口的实现:
package org.iti.wxl.springaop;
public class UserServiceImpl implements UserService {
@Override
public String getUser(String userId) {
System.out.println("this is getUser() method!");
return "user";
}
@Override
public void addUser() {
System.out.println("this is addUser() method!");
}
}
定义切面:
package org.iti.wxl.springaop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class MyInterceptor {
@Pointcut("execution(* org.iti.wxl.springaop..*.*(..))")
private void pointCutmethod(){
}
@Before("pointCutmethod() && args(userId)")
public void doBefore(String userId){
System.out.println("前置通知 " + userId);
}
@AfterReturning("pointCutmethod()")
public void doAfterReturning(){
System.out.println("后置通知");
}
@AfterThrowing("pointCutmethod()")
public void doAfterException(){
System.out.println("异常通知");
}
@After("pointCutmethod()")
public void doAfter(){
System.out.println("最终通知");
}
@Around("pointCutmethod()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("环绕开始");
Object object = pjp.proceed();
System.out.println("环绕结束");
return object;
}
}
说明:
第一个*表示方法的返回值,这里使用通配符,只有返回值符合条件的才拦截(!void表示有返回值)。
第一个..表示com.royzhou.aop包及其子包。
倒数第二个*表示包下的所有Java类都被拦截。
最后一个*表示类的所有方法都被拦截。
(..)表示方法的参数可以任意多个,如[(java.lang.String,java.lang.Integer)表示第一个参数是String,第二个参数是int的方法才会被拦截]
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- 使用 annotation -->
<context:annotation-config />
<!-- 启用aop -->
<aop:aspectj-autoproxy proxy-target-class="true" />
<bean id="myInterceptor" class="org.iti.wxl.springaop.MyInterceptor"/>
<bean id="userService" class="org.iti.wxl.springaop.UserServiceImpl"/>
</beans>
测试类:
package org.iti.wxl.springaop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringAOP {
public static void main(String[] args) {
ApplicationContext cxt = new ClassPathXmlApplicationContext("bean.xml");
UserService userService = (UserService)cxt.getBean("userService");
userService.getUser("user1");
System.out.println("===========");
userService.addUser();
}
}
运行结果:
前置通知 user1
环绕开始
this is getUser() method!
后置通知
最终通知
环绕结束
===========
环绕开始
this is addUser() method!
后置通知
最终通知
环绕结束
在项目开发中,AOP主要用来配置spring的声明式事务管理,它还可用在日志管理,性能监测等。它为程序员编程提供了一种新思路,我们可以不断去发现它的新用途。
分享到:
相关推荐
本篇将详细探讨JDK动态代理和Spring AOP,以及它们在实际应用中的作用。 首先,JDK动态代理是Java提供的一种在运行时创建代理对象的技术。它允许我们在不修改原有类的基础上,为已有接口添加额外的功能。动态代理的...
现在让我们深入探讨JDK动态代理和Spring AOP的原理。 首先,JDK动态代理基于Java的反射机制,通过`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口来实现。Proxy类用于创建一个代理对象,...
在Java中,我们可以使用JDK的动态代理或者Spring AOP来实现代理模式。 JDK动态代理主要依赖于`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口。Proxy类是生成代理对象的工厂,而...
在Spring中,AOP主要通过两种动态代理技术实现:JDK动态代理和CGLIB动态代理。 首先,让我们详细了解一下JDK动态代理。JDK动态代理基于Java的接口实现,它适用于目标对象实现了至少一个接口的情况。在运行时,JDK...
Spring AOP 的底层实现技术 --- Jdk 动态代理原理 JDK 动态代理是 Spring AOP 的底层实现技术,允许开发者在运行期创建接口的代理实例。在 JDK 1.3 以后,JDK 动态代理技术提供了实现 AOP 的绝好底层技术。JDK 动态...
本篇将详细讲解Spring中的AOP实现,特别是JDK动态代理的应用。 首先,我们要了解什么是AOP(Aspect Oriented Programming,面向切面编程)。AOP是一种编程范式,旨在解决应用程序中分散的、横切关注点的问题,如...
本文将深入探讨Spring是如何通过JDK的动态代理来实现AOP的。 首先,我们要理解JDK动态代理的基本原理。在Java中,动态代理主要由`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口组成。...
本篇文章将探讨如何通过JDK动态代理实现Spring AOP的基础知识。 首先,我们要理解什么是JDK动态代理。在Java中,动态代理机制允许我们在运行时创建一个实现了特定接口的新类。这个新类的实例可以代理目标对象,执行...
Spring AOP提供了两种代理方式:JDK动态代理和CGLIB代理。JDK动态代理用于目标对象实现接口的情况,而CGLIB代理则用于目标对象没有实现接口的情况。Spring默认使用JDK动态代理,但如果目标对象没有实现接口,它会...
Spring 框架中 JDK 动态代理和 CGLIB 动态代理是 Spring AOP 中一个非常重要的知识点。Spring AOP 框架会根据实际情况选择使用 JDK 的动态代理还是 CGLIB 的动态代理。 JDK 动态代理是 Java 自带的动态代理机制,它...
Spring AOP支持不同的代理策略,包括JDK动态代理和CGLIB代理。如果被代理的类没有实现接口,Spring AOP会采用CGLIB来生成代理对象。CGLIB(Code Generation Library)是一个开源的代码生成库,它允许运行时在内存中...
Spring AOP允许我们通过代理来实现横切关注点,如日志、事务管理等,而JDK动态代理则是Spring AOP实现的一种方式。本文将深入探讨Spring如何利用JDK动态代理技术来实现这一功能,并通过实例解析其底层实现。 首先,...
Spring框架是AOP实现的一个典范,它提供了两种主要的动态代理方式:JDK动态代理和CGLib动态代理。 **JDK动态代理**: JDK动态代理基于Java的反射API实现,适用于接口代理。当目标对象实现了至少一个接口时,Spring...
Spring AOP默认使用JDK动态代理,但如果目标类没有实现接口,它会自动切换到CGLIB。在"通过Configuration文件实现AOP.docx"文档中,可能会详细讲述如何在Spring配置文件中配置AOP代理,包括如何选择使用JDK动态代理...
本文将深入探讨Spring AOP中的JDK动态代理机制。 首先,我们要理解什么是动态代理。动态代理是在运行时创建一个实现了一组给定接口的代理类,这个代理类可以拦截并处理方法调用,从而实现一些额外的功能。JDK的动态...
在 Spring 中,AOP 的实现主要依赖于代理模式,有两种代理方式:JDK 动态代理和 CGLIB 动态代理。 JDK 动态代理是基于接口的,它要求被代理的目标对象必须实现至少一个接口。Spring 使用 `java.lang.reflect.Proxy`...
3. **代理选择**:Spring默认优先使用JDK动态代理,如果无法满足条件(即目标类没有实现接口),则会自动切换到CGLIB。可以通过配置`proxyTargetClass="true"`来强制使用CGLIB。 4. **代理对象的获取**:通常,...
2. **动态代理**:Spring AOP 的默认代理方式是动态代理,它包括JDK动态代理和CGLIB代理。当目标对象实现了至少一个接口时,Spring将使用JDK的动态代理机制。JDK动态代理通过实现InvocationHandler接口,并在运行时...
Spring AOP(面向切面编程)也与此密切相关,它使用动态代理来实现切面的织入,从而提供横切关注点,如日志、事务管理等。现在,我们深入探讨Java动态代理和Spring AOP。 首先,让我们从Java动态代理开始。在Java中...