java的动态代理的两种方式和spring的aop面向切面编程的对比
Posted jeasonchen001
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java的动态代理的两种方式和spring的aop面向切面编程的对比相关的知识,希望对你有一定的参考价值。
java动态代理的两种方式
使用动态代理的好处:可以进行类的功能的加强,同时减少耦合和代码的冗余,耦合的意思是不用吧加强的部分写到各个实现类里面,冗余的意思是如果对每个实现类加强的部分是一样的,通过一个代理类即可实现
- 基于jdk的动态代理
通过jdk中自带的Proxy类进行动态的代理,Proxy创建动态代理对象的时候要传入三个参数,第一个是classloader,第二个是interfaces,第三个是代理类实现的方法
要求:代理的是一个接口,必须至少有一个实现类
创建接口的代码:
/** * author:Chen * date:2019/10/7 14:04 */ public interface IActor public void sing(String money); public void actor(); public class Actor implements IActor //只要参数传进来的时候是有钱的 public void sing(String money) System.out.println("演员唱歌"); public void actor() System.out.println("演员演戏"); /** * 使用jdk自带的Proxy类实现动态代理 */ @Test public void demo04() //创建一个接口的实现类的对象 final Actor actor=new Actor(); IActor proxyActor = (IActor)Proxy.newProxyInstance(actor.getClass().getClassLoader(), Actor.class.getInterfaces(), new InvocationHandler() public Object invoke(Object proxy, Method method, Object[] args) throws Throwable //将实现类的对象作为对象传入进去执行对应重写的方法 Object proxy_actor=null; String name = method.getName(); if(name.equals("sing")) double money = Double.parseDouble((String)args[0]); if (money>1000d)//可以对金额进行判断,同时可以将一些不合法的参数进剔除 proxy_actor= method.invoke(actor, args); else System.out.println("不能唱歌,钱太少了"); return proxy_actor;//必须要将invoke执行返回的代理对象返回 ); //将钱交给经纪人进行判定是否要唱歌,实现了动态代理的功能 proxyActor.sing("1000");
tips:无法通过返回值的类型来判定重载,必须通过参数的个数、参数的类型、参数的顺序来判定重载。返回值无法判定重载的原因是
调用方法的时候没有指定返回值的类型,编译器不知道要调用哪个方法
好处:不用接口,可以轻易的将一个类的所有方法进行代理,也就是更改,而不改变原始的类,缺点是所有的方法都会进行拦截。
- 使用CGLib中的Enhancer类来创建代理对象
/** * 必须要引入cglib的包 <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.1</version> </dependency> * 执行被代理类的方法的时候,进行拦截,不需要实现接口 */ @Test public void demo05() final Actor actor = new Actor(); Actor proxy_actor = (Actor) Enhancer.create(Actor.class, new MethodInterceptor() //创建一个方法拦截器来进行拦截 public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable Object rtvalue = null; if (method.getName().equals("sing")) if (Double.parseDouble((String) args[0]) > 1000) rtvalue = method.invoke(actor, args); else System.out.println("不能唱歌"); return rtvalue; ); proxy_actor.sing("999");
- spring的aop面向对象编程的方式
通过aop接口进行事务的控制
aop中的相关的术语:
Joinpoint:连接点
pointCut:切入点,需要代理的业务方法就是切入点
aspect:切面,就是要放在切入点前后执行的一个对象,将这个对象的方法配置成切入点的各种通知
before:前置通知,在切入点执行之前执行
after-returning:后置通知,当切入点执行完成的时候执行
after-throwing:异常通知,当发生异常的时候执行
after:最终通知,无论发生什么,在最后执行
切入点表达式:execution(* com.huawei.sevice.impl.*.*(..)) 返回值类型(用通配符*表示) 包名.类名.方法名() ..代表的是通配有参和无参 也可以完整写法通配的写法为 * *..*.*(..) *..通配所有的包名 tips:在引入依赖的时候一定要引入切入点表达式的解析包
Advice:增强
Introduce:引介
一个小demo,用前置,后置,异常,最终通知配置,将logger类的方法加入进去 spring的配置文件 完整的spring约束 <?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" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!--将切入点的bean配置--> <bean id="accountService" class="com.huawei.service.impl.AccountServiceImpl"></bean> <!--将切面的bean进行配置--> <bean id="logger" class="com.huawei.utils.Logger"></bean> <!--配置切面--> <aop:config> <aop:aspect id="loggeradvice" ref="logger" > <!--前置通知--> <aop:before method="before_printLog" pointcut="execution(* com.huawei.service.impl.AccountServiceImpl.*(..))"></aop:before> <!--后置通知--> <aop:after-returning method="afterreturning_printLog" pointcut="execution(* com.huawei.service.impl.AccountServiceImpl.*(..))" ></aop:after-returning> <!--异常通知--> <aop:after-throwing method="afterthrowing_printLog" pointcut="execution(* com.huawei.service.impl.AccountServiceImpl.*(..))"></aop:after-throwing> <!--最终通知--> <aop:after method="after_printLog" pointcut="execution(* com.huawei.service.impl.AccountServiceImpl.*(..))"></aop:after> </aop:aspect> </aop:config> </beans> public class SpringTest public static void main(String[] args) //必须通过spring的方式获取的对象,才能实现aop ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml"); AccountService accountService = (AccountService)applicationContext.getBean("accountService"); accountService.saveAccount(account);//执行的时候将携带那些通知 小demo,通过在代码中写代码进行环绕通知的配置 <?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" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!--将切入点的bean配置--> <bean id="accountService" class="com.huawei.service.impl.AccountServiceImpl"></bean> <!--将切面的bean进行配置--> <bean id="logger" class="com.huawei.utils.Logger"></bean> <!--配置切面--> <aop:config> <!--配置通用的切入点--> <aop:pointcut id="pt-1" expression="execution(* com.huawei.service.impl.AccountServiceImpl.*(..))"></aop:pointcut> <aop:aspect id="loggeradvice" ref="logger" > <!-- <!–前置通知–> <aop:before method="before_printLog" pointcut="execution(* com.huawei.service.impl.AccountServiceImpl.*(..))"></aop:before> <!–后置通知–> <aop:after-returning method="afterreturning_printLog" pointcut="execution(* com.huawei.service.impl.AccountServiceImpl.*(..))" ></aop:after-returning> <!–异常通知–> <aop:after-throwing method="afterthrowing_printLog" pointcut="execution(* com.huawei.service.impl.AccountServiceImpl.*(..))"></aop:after-throwing> <!–最终通知–> <aop:after method="after_printLog" pointcut="execution(* com.huawei.service.impl.AccountServiceImpl.*(..))"></aop:after>--> <!--环绕通知--> <aop:around method="around_printLog" pointcut-ref="pt-1"></aop:around> </aop:aspect> </aop:config> </beans>
以上是关于java的动态代理的两种方式和spring的aop面向切面编程的对比的主要内容,如果未能解决你的问题,请参考以下文章
Spring的两种动态代理:Jdk和Cglib 的区别和实现
Spring的两种动态代理:Jdk和Cglib 的区别和实现