Spring AOP编程(二)-AOP实现的三种方式
AOP的实现有三种方式:
l aop底层将采用代理机制进行实现。
l 接口 + 实现类 :spring采用 jdk 的动态代理Proxy。
l 实现类:spring 采用 cglib字节码增强。
一.手工方式
1.JDK动态代理
JDK动态代理 对“装饰者”设计模式 简化。使用前提:必须有接口
1.目标类:接口 + 实现类
2.切面类:用于存通知 MyAspect
3.工厂类:编写工厂生成代理
4.测试
1.目标类
UserService.java
1 2 3 4 5 6 7 | package com.zk.a_jdk; public interface UserService { public void addUser(); public void updateUser(); public void deleteUser(); } |
UserServiceImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | package com.zk.a_jdk; public class UserServiceImpl implements UserService{ @Override public void addUser() { // TODO Auto-generated method stub System.out.println( "proxy addUser" ); } @Override public void updateUser() { // TODO Auto-generated method stub System.out.println( "proxy updateUser" ); } @Override public void deleteUser() { // TODO Auto-generated method stub System.out.println( "proxy deleteUser" ); } } |
2.切面类
MyAspect.java
1 2 3 4 5 6 7 8 9 10 11 12 | package com.zk.a_jdk; public class MyAspect { public void before(){ System.out.println( "鸡头" ); } public void after(){ System.out.println( "牛后" ); } } |
3.工厂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | package com.zk.a_jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class MyBeanFactory { //手工代理 public static UserService createService(){ //1.目标类 final UserService userservice= new UserServiceImpl(); //2.切面类 final MyAspect myAspect= new MyAspect(); //3.代理类:将目标类(切入点)和切面类(通知)结合-->切面 //Proxy.newProxyInstance /* * 参数一:loader类加载器,动态代理类,运行时创建,任何类都需要类加载器将其加载至内存。 * 一般情况下:当前类,class.getClassLoader(); * 目标类实例:getClass().get... * 参数二:interfaces,代理类需要实现的所有接口 * 方式一:目标类实例.getClass().getInterfaces();注意:只能获得自己的接口,获得不到父元素的接口 * 方式二:new Class[]{UserService.class} * 例如:jdbc驱动 * 参数三:InvocationHandler 处理类,接口,必须进行实现类,一般采用匿名内部类 * 提供invoke方法,代理类每一个方法执行时,都将去调用invoke * 参数三.1.Object proxy代理对象 * 参数三.2.Method method 代理对象当前方法的描述对象(反射) * 执行方法方法名:method.getName(); * 执行方法:method.invoke(对象,实际参数) * 参数三.3 Object[] args 方法实际参数 */ UserService proxyService=(UserService)Proxy.newProxyInstance (MyBeanFactory. class .getClassLoader(), userservice.getClass().getInterfaces(), new InvocationHandler(){ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub //前执行 myAspect.before(); //执行目标类的方法 Object obj=method.invoke(userservice, args); //后执行 myAspect.after(); return null ; } }); return proxyService; } } |
4.测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | package com.zk.a_jdk; import org.junit.Test; public class TestJDK { @Test public void test(){ UserService userservice=MyBeanFactory.createService(); userservice.addUser(); userservice.deleteUser(); userservice.updateUser(); } } |
运行效果:
2. CGLIB字节码增强
l 没有接口,只有实现类。
l 采用字节码增强框架 cglib,在运行时 创建目标类的子类,从而对目标类进行增强。
l 导入jar包:
1.目标类
UserService.java
1 2 3 4 5 6 7 | package com.zk.a_jdk; public interface UserService { public void addUser(); public void updateUser(); public void deleteUser(); } |
UserServiceImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | package com.zk.a_jdk; public class UserServiceImpl implements UserService{ @Override public void addUser() { // TODO Auto-generated method stub System.out.println( "proxy addUser" ); } @Override public void updateUser() { // TODO Auto-generated method stub System.out.println( "proxy updateUser" ); } @Override public void deleteUser() { // TODO Auto-generated method stub System.out.println( "proxy deleteUser" ); } } |
2.切面类
MyAspect.java
1 2 3 4 5 6 7 8 9 10 11 12 | package com.zk.a_jdk; public class MyAspect { public void before(){ System.out.println( "鸡头" ); } public void after(){ System.out.println( "牛后" ); } } |
3.MyBeanFactory.java工厂类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | package com.zk.b_cglib; import java.lang.reflect.Method; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; public class MyBeanFactory { //手工代理 public static UserService createService(){ //1.目标类 final UserServiceImpl userservice= new UserServiceImpl(); //2.切面类 final MyAspect myAspect= new MyAspect(); /*3.代理类 * 采用字节码增强框架-cglib,程序运行时创建目标类的子类,从而对目标类进行增强 * 导入jar包 * intercept等效于jdk中invoke方法 * 参数一二三 与invoke相同 * 参数四方法的代理 */ Enhancer enhance= new Enhancer(); //确定父类 enhance.setSuperclass(userservice.getClass()); enhance.setCallback( new MethodInterceptor(){ //设置回调函数,MethodInterceptor接口等效 jdk InvocationHandler接口 @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodproxy) throws Throwable { // TODO Auto-generated method stub //前before myAspect.before(); //执行目标类的方法 Object obj=method.invoke(userservice, args); //执行代理类的父类 methodproxy.invokeSuper(proxy, args); //后after myAspect.after(); return null ; } }); //创建代理 UserServiceImpl proxyservice=(UserServiceImpl) enhance.create(); return proxyservice; } } |
4.TestCglib.java测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | package com.zk.b_cglib; import org.junit.Test; public class Testcglib { @Test public void test(){ UserService userservice=MyBeanFactory.createService(); userservice.addUser(); userservice.deleteUser(); userservice.updateUser(); } } |
运行效果图:
二.半自动方式
让spring 创建代理对象,从spring容器中手动的获取代理对象。
导入jar包:
AOP:AOP联盟(规范)、spring-aop (实现)
1.目标类
UserService.java
1 2 3 4 5 | public interface UserService { public void addUser(); public void updateUser(); public void deleteUser(); } |
UserServiceImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | package com.zk.springAop; public class UserServiceImpl implements UserService{ @Override public void addUser() { // TODO Auto-generated method stub System.out.println( "addUser" ); } @Override public void updateUser() { // TODO Auto-generated method stub System.out.println( "updateUser" ); } @Override public void deleteUser() { // TODO Auto-generated method stub System.out.println( "deleteUser" ); } } |
2.切面类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /** * 切面类中确定通知,需要实现不同接口,接口就是规范,从而就确定方法名称。 * * 采用“环绕通知” MethodInterceptor * */ public class MyAspect implements MethodInterceptor { @Override public Object invoke(MethodInvocation mi) throws Throwable { System.out.println( "前3" ); //手动执行目标方法 Object obj = mi.proceed(); System.out.println( "后3" ); return obj; } } |
3.spring配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <?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:p= "http://www.springframework.org/schema/p" xmlns:context= "http://www.springframework.org/schema/context" 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 "> <!-- 创建目标类 --> <bean id= "userserviceid" class = "com.zk.factorybean.UserServiceImpl" ></bean> <!-- 创建切面类 --> <bean id= "aspectid" class = "com.zk.factorybean.MyAspect" ></bean> <!-- 创建代理类 使用工厂bean factorybean,底层调用getObject(), 返回特殊bean ProxyBeanFactory用于创建代理工厂bean,生成特殊代理对象 interface 确定接口 通过Array确定多个值 只有一个值时,value= "" target确定目标类 interceptorNames:通知切面类名称,类型String[],如果设置一个值, value= "" optimize:强制使用cglib <property name= "optimized value=" true "></property> 底层机制: 如果目标类有接口,采用jdk代理 如果没有接口,采用cglib代理 如果声明式optimize= true ,都使用cglib --> <bean id= "proxyServiceid" class = "org.springframework.aop.framework.ProxyFactoryBean" > <property name= "interfaces" value= "com.zk.factorybean.UserService" ></property> <property name= "target" ref= "userserviceid" ></property> <property name= "interceptorNames" value= "aspectid" ></property> </bean> </beans> |
4.Testfactorybean.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package com.zk.factorybean; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Testfactorybean { @Test public void test(){ String path= "com/zk/factorybean/ApplicationContext.xml" ; ApplicationContext ac= new ClassPathXmlApplicationContext(path); UserService userservice=(UserService) ac.getBean( "proxyServiceid" ); userservice.addUser(); userservice.deleteUser(); userservice.updateUser(); } } |
运行效果:
三.spring aop编程:全自动
从spring容器获得目标类,如果配置aop,spring将自动生成代理。
要确定目标类,aspectj 切入点表达式,导入jar包spring-framework-3.0.2.RELEASE-dependencies\org.aspectj\com.springsource.org.aspectj.weaver\1.6.8.RELEASE
1.目标类
UserService.java
1 2 3 4 5 | public interface UserService { public void addUser(); public void updateUser(); public void deleteUser(); } |
UserServiceImpl.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | package com.zk.springAop; public class UserServiceImpl implements UserService{ @Override public void addUser() { // TODO Auto-generated method stub System.out.println( "addUser" ); } @Override public void updateUser() { // TODO Auto-generated method stub System.out.println( "updateUser" ); } @Override public void deleteUser() { // TODO Auto-generated method stub System.out.println( "deleteUser" ); } } |
2.切面类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /** * 切面类中确定通知,需要实现不同接口,接口就是规范,从而就确定方法名称。 * * 采用“环绕通知” MethodInterceptor * */ public class MyAspect implements MethodInterceptor { @Override public Object invoke(MethodInvocation mi) throws Throwable { System.out.println( "前3" ); //手动执行目标方法 Object obj = mi.proceed(); System.out.println( "后3" ); return obj; } } |
3.spring配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <?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:p= "http://www.springframework.org/schema/p" 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.xsd "> <!-- 创建目标类 --> <bean id= "userserviceid" class = "com.zk.springAop.UserServiceImpl" ></bean> <!-- 创建切面类 --> <bean id= "aspectid" class = "com.zk.springAop.MyAspect" ></bean> <!-- Aop编程 1 .导入命名空间 2 .使用<aop:config>进行配置 proxy-target- class = "true" 声明是使用cglib代理 <aop:pointcut>:切入点,从目标对象上获取具体的方法 <aop:advisor>特殊的切面,只有一个通知和一个切入点 advise-ref 通知引用 pointcut-ref 切入点引用 advisor通知 3 .切入点表达式 execution(* com.zk.springAop.*.*(..)) 选择方法 *表示返回值任意 包 类名任意. 方法名任意 . 参数任意 . --> <aop:config> <aop:pointcut expression= "execution(* com.zk.springAop.*.*(..))" id= "myPointCut" /> <aop:advisor advice-ref= "aspectid" pointcut-ref= "myPointCut" /> </aop:config> </beans> |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)