转自: Java 动态代理与AOP - 如果的事 - 博客园动态代理与AOP 代理模式 代理模式给某一个目标对象(target)提供代理对象(proxy),并由代理对象控制对target对象的引用。 模式图: 代理模式中的角色有: 抽象对象角色(Abstrachttps://www.cnblogs.com/chenny7/p/11201010.html
【1】代理模式
/*** 抽象对象角色*/
abstract class AbstractObject {public abstract void operation();
}
/*** 目标对象*/
class TargetObject extends AbstractObject {public void operation() {System.out.println("Do Something!");}
}
/*** 代理对象*/
public class ProxyObject extends AbstractObject {TargetObject targetObject = new TargetObject();@Overridepublic void operation() {System.out.println("do sth before");targetObject.operation();System.out.println("do sth after");}public static void main(String[] args) {new ProxyObject().operation();}
}
代理模式中的角色有:
- 抽象对象角色(AbstractObject):声明了目标对象和代理对象的共同接口,这样依赖在任何可以使用目标对象的地方都可以使用代理对象。
- 目标对象角色(RealObject):定义了代理对象所代表的目标对象。
- 代理对象角色(ProxyObject):代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或者之后,执行某个操作,而不是单纯的将调用传递给目标对象。
【2】静态代理与动态代理
按照代理类的创建时期,可分为静态代理和动态代理:
- 静态代理:由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。
- 动态代理:在程序运行时运用反射机制动态创建而成。
【2.1】静态代理
/*** 会飞接口*/
interface Flyable {void fly(long ms);
}
/*** 会飞的鸟*/
class Bird implements Flyable {@Overridepublic void fly(long ms) {System.out.println("bird is flying.");try {Thread.sleep(ms);} catch (Exception e ) {System.out.println("bird睡眠异常");}}
}
/*** 会飞的风筝*/
class Kite implements Flyable {@Overridepublic void fly(long ms) {System.out.println("kite is flying.");try {Thread.sleep(ms);} catch (Exception e ) {System.out.println("kite 睡眠异常");}}
}
/*** 静态代理*/
public class StaticProxy implements Flyable {private Flyable flyable;public StaticProxy(Flyable flyable) {this.flyable = flyable;}@Overridepublic void fly(long ms) {System.out.println("before fly");flyable.fly(ms);System.out.println("after fly");}public static void main(String[] args) {new StaticProxy(new Kite()).fly(1000);new StaticProxy(new Bird()).fly(1000);}
}
静态代理缺点:
- 若接口 Flyable 增加一个方法,则目标对象(接口实现类)与代理类全都需要增加方法实现,全都需要修改代码;
【2.2】动态代理
/*** 动态代理*/
public class DynamicProxy implements InvocationHandler {private Object targetObject;public Object newProxyInstance(Object targetObject) {this.targetObject = targetObject;return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("before invoke");proxy = method.invoke(targetObject, args);System.out.println("before after");return proxy;}public static void main(String[] args) {DynamicProxy dProxy = new DynamicProxy();// 会飞的鸟Flyable bird = (Flyable)dProxy.newProxyInstance(new Bird());bird.fly(1000);// 风筝Flyable kite = (Flyable)dProxy.newProxyInstance(new Kite());kite.fly(1000);}
}
显然, 动态代理对象不需要实现目标对象接口,但目标对象一定要实现接口,否则不能使用代理;
【3】cglib 代理
1)应用场景:
- 有的时候,目标对象可能只是一个单独的对象,并没有实现任何的接口,这个时候,我们就可以使用目标对象子类的方式实现代理,这种代理方式就是:Cglib代理,也叫做子类代理,它是在内存中构件一个子类对象,从而实现对目标对象的功能拓展。
2)cglib 介绍
- Cglib是强大的高性能的代码生成包,它可以在运行期间拓展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)。
- Cglib包的底层是通过使用一个小而快的字节码处理框架ASM来转换字节码并生成新的类,不鼓励直接只使用ASM,因为它要求你必须对JVM内部结构,包括class文件的格式和指令集都很熟悉。
class Plane {public void fly(long ms) {System.out.println("plane is flying");try {Thread.sleep(ms);} catch(Exception e) {System.out.println("plane睡眠异常");}}
}
public class CglibProxy implements MethodInterceptor {private Object target;public CglibProxy(Object target) {this.target = target;}public Object getProxyInstance() {Enhancer enhancer = new Enhancer(); // 1 实例化工具类enhancer.setSuperclass(this.target.getClass()); // 设置父类对象enhancer.setCallback(this); // 设置回调函数return enhancer.create(); // 创建子类,也就是代理对象}// 拦截器方法@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("before invoke");Object returnValue = method.invoke(target, objects);System.out.println("after invoke");return returnValue;}public static void main(String[] args) {CglibProxy cglibProxy = new CglibProxy(new Plane());Plane plane = (Plane)cglibProxy.getProxyInstance();plane.fly(1000);}
}
maven pom.xml
<!-- https://mvnrepository.com/artifact/cglib/cglib --><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version></dependency>
【4】 spring aop
1)Spring在新版本中对AOP功能进行了增强,体现在这么几个方面:
- 在XML配置文件中为AOP提供了aop命名空间
- 增加了AspectJ切点表达式语言的支持
- 可以无缝地集成AspectJ
2)如何使用 引介切面(Introduction Advisor)为一个现有对象添加任何接口的实现:
2.1)定义两个接口及其实现类,包括 服务员与售货员;
public class SpringAopDef {
}
interface Waiter { // 服务员接口void greetTo(String client);void serveTo(String client);
}
class NaiveWaiter implements Waiter { // 服务员实现类public void greetTo(String client) {System.out.println("NaiveWaiter greet to " + client);}public void serveTo(String client) {System.out.println("NaiveWaiter serve to " + client);}
}
interface Seller {// 售货员接口int sell(String goods, String client);
}
class SmartSeller implements Seller { // 售货员实现类public int sell(String goods, String client) {System.out.println("a smart seller sells " + goods + " to " + client);return 100;}
}
2.2)下一步,我们想让 服务员充当售货员角色,可以卖东西;
引入切面:
@Aspect
public class EnableSellerAspect {@DeclareParents(value="com.swjtu.mybatis.proxy.springaop.NaiveWaiter" // 切点-目标类, defaultImpl = SmartSeller.class) // 增强类public Seller seller; // 增强类接口
}
maven pom 引入spring依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.swjtu.mybatis</groupId><artifactId>MybatisHello2</artifactId><version>0.0.1-SNAPSHOT</version><properties><spring.version>5.2.0.RELEASE</spring.version></properties>
.................
<dependencies><dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.9.4</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version></dependency><!-- Spring Dependencies --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency></dependencies>
beans.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"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.0.xsdhttp://www.springframework.org/schema/context/http://www.springframework.org/schema/context/spring-context.xsd"><aop:aspectj-autoproxy/><bean id="waiter" class="com.swjtu.mybatis.proxy.springaop.NaiveWaiter"/><bean class="com.swjtu.mybatis.proxy.springaop.EnableSellerAspect"/><!-- 定义切面 --><bean id="testBeforeAdvice" class="com.swjtu.mybatis.proxy.springaop.advice.TestBeforeAdvice"/><aop:config proxy-target-class="true"><aop:advisor advice-ref="testBeforeAdvice" pointcut="execution(* com..*.Waiter.greetTo(..))"/></aop:config></beans>
切面如下:
public class TestBeforeAdvice implements MethodBeforeAdvice {@Overridepublic void before(Method method, Object[] objects, Object o) throws Throwable {System.out.println("before invoke");System.out.println("do busi");System.out.println("after invoke");}
}
当调用 Waiter.greetTo() 方法会调用 before 通知;
springaop 测试用例入口:
public class SpringAopMain {public static void main(String[] args) {// 获取上下文环境ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");Waiter waiter = (Waiter)context.getBean("waiter"); // 从上下文中获取bean// 调用服务员原有方法waiter.greetTo("zhangsan");waiter.serveTo("zhangsan");// 通过切面已经将 Waiter 实现了 Seller 接口,所以可以强制转换Seller seller = (Seller) waiter;seller.sell("apple", "zhangsan");}
}
// spring aop 打印日志
before invoke
do busi
after invoke
NaiveWaiter greet to zhangsan
NaiveWaiter serve to zhangsan
a smart seller sells apple to zhangsan