版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、AOP编程中注解参数详解Pointcut(execution(* transfer(.) private void anyOldTransfer() 切入点指定者的支持Spring AOP 支持在切入点表达式中使用如下的 AspectJ 切入点指定者:1: execution :匹配方法执行的连接点,这是你将会用到的 Spring 的最主要的切入点指定 者。2: with in :限定匹配特定类型的连接点(在使用Spring AOP的时候,在匹配的类型中定义的方法的执行)。3: this :限定匹配特定的连接点 (使用Spring AOP的时候方法的执行),其中bean referenee (
2、Spring AOP 代理)是指定类型的实例。4: target :限定匹配特定的连接点(使用 Spring AOP 的时候方法的执行),其中目标对 象(被代理的 appolieation objeet )是指定类型的实例。5: args :限定匹配特定的连接点(使用 Spring AOP 的时候方法的执行),其中参数是指 定类型的实例。6: target :限定匹配特定的连接点(使用Spring AOP的时候方法的执行),其中执行的对象的类已经有指定类型的注解。7: args :限定匹配特定的连接点(使用 Spring AOP的时候方法的执行),其中实际传入 参数的运行时类型有指定类型的注解
3、。8: within :限定匹配特定的连接点, 其中连接点所在类型已指定注解 (在使用 Spring AOP 的时候,所执行的方法所在类型已指定注解)。9: annotation :限定匹配特定的连接点(使用Spring AOP的时候方法的执行),其中连接点的主题有某种给定的注解合并切入点表达式 切入点表达式可以使用 &, | 和 ! 来合并 .还可以通过名字来指向切入点表达式。 切入点表达式的基本语法Spring AOP 用户可能会经常使用 exeeution pointeut designator。执行表达式的格式如下: exeeution(modifiers-pattern? ret-t
4、ype-pattern deelaring-type-pattern? name-pattern(param-pattern) throws-pattern?)除了返回类型模式(上面代码片断中的 ret-type-pattern ),名字模式和参数模式以外, 所有的部分都是可选的。 返回类型模式决定了方法的返回类型必须依次匹配一个连接点。类型匹配模式1:* :匹配任何数量字符; 比如模式 (*,String) 匹配了一个接受两个参数的方法, 第一个 可以是任意类型,第二个则必须是 String 类型2: . :匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式 中匹配任何
5、数量参数,可以使零到多个。3: + :匹配指定类型的子类型;仅能作为后缀放在类型模式后边。类型匹配模式示例1: java.lang.String匹配 String 类型;2: java.*.String匹配 java 包下的任何“一级子包”下的 String 类型;如匹配 java.lang.String,但不匹配 java.lang.ss.String3: java.*匹配 java 包及任何子包下的任何类型 ;如匹配 java.lang.String、 java.lang.annotation.Annotation4: java.lang.*ing匹配任何 java.lang 包下的以 i
6、ng 结尾的类型;5: java.lang.Number+ 匹配 java.lang 包下的任何 Number的子类型;如匹配 java.lang.Integer ,也匹配 java.math.BigInteger切入点表达式的基本示例,使用 execution1: public * *(.)任何公共方法的执行2: * cn.javass.IPointcutService.*()cn.javass 包及所有子包下 IPointcutService 接口中的任何无参方法3: * cn.javass.*.*(.)cn.javass 包及所有子包下任何类的任何方法4: * cn.javass.IPo
7、intcutService.*(*)cn.javass 包及所有子包下 IPointcutService 接口的任何只有一个参数方法5: * (!cn.javass.IPointcutService+).*(.)非“ cn.javass 包及所有子包下 IPointcutService 接口及子类型”的任何方法6: * cn.javass.IPointcutService+.*()cn.javass 包及所有子包下 IPointcutService 接口及子类型的的任何无参方法7: * cn.javass.IPointcut*.test*(java.util.Date)cn.javass 包及
8、所有子包下 IPointcut 前缀类型的的以 test 开头的只有一个参数类型为 java.util.Date 的方法,注意该匹配是根据方法签名的参数类型进行匹配的,而不是根据 执行时传入的参数类型决定的如定义方法: public void test(Object obj);即使执行时传入 java.util.Date ,也不会匹配的。8: * cn.javass.IPointcut*.test*(.) throws IllegalArgumentException, ArrayIndexOutOfBoundsExceptioncn.javass 包及所有子包下 IPointcut 前缀类型
9、的的任何方法,且抛出 IllegalArgumentException 和 ArrayIndexOutOfBoundsException 异常9: * (cn.javass.IPointcutService+ & java.io.Serializable+).*(.)任何实现了 cn.javass 包及所有子包下 IPointcutService 接口和 java.io.Serializable 接口的类型的任何方法10: java.lang.Deprecated * *(.)任何持有 java.lang.Deprecated 注解的方法11: java.lang.Deprecated cn.
10、javass.Secure * *(.)任何持有 java.lang.Deprecated和 cn.javass.Secure注解的方法12: (java.lang.Deprecated | cn.javass.Secure) * *(.)任何持有 java.lang.Deprecated或 cn.javass.Secure注解的方法13: (cn.javass.Secure *) *(.) 任何返回值类型持有 cn.javass.Secure 的方法14: * (cn.javass.Secure *).*(.) 任何定义方法的类型持有 cn.javass.Secure 的方法15: * *(
11、cn.javass.Secure (*) , cn.javass.Secure (*) 任何签名带有两个参数的方法,且这个两个参数都被 Secure 标记了,如 public void test(Secure String str1, Secure String str1);16: * *( cn.javass.Secure *)或 * *( cn.javass.Secure *)任何带有一个参数的方法,且该参数类型持有 cn.javass.Secure;如 public voidtest(Model model); 且 Model 类上持有 Secure注解17: * *(cn.javass
12、.Secure (cn.javass.Secure *) , cn.javass.Secure(cn.javass.Secure *)任何带有两个参数的方法,且这两个参数都被cn.javass.Secure标记了;且这两个参数的类型上都持有 cn.javass.Secure;18: * *(java.util.Map, .)任何带有一个 java.util.Map 参数的方法,且该参数类型是以为泛型参数;注意只匹配第一个参数为 java.util.Map, 不包括子类型;如 public void test(HashMap map, String str);将不匹配,必须使用“*(java.u
13、til.HashMap,.) ”进行匹配;而 publicvoid test(Map map, int i);也将不匹配,因为泛型参数不匹配19: * *(java.util.Collection)任何带有一个参数(类型为 java.util.Collection )的方法,且该参数类型是有一个泛型 参数,该泛型参数类型上持有cn.javass.Secure注解;如 public voidtest(Collection collection);Model 类型上持有 cn.javass.Secure 切入点表达式的基本示例,使用 within 匹配指定类型内的方法1: within(cn.ja
14、vass.*)cn.javass 包及子包下的任何方法执行2: within(cn.javass.IPointcutService+)cn.javass 包或所有子包下 IPointcutService 类型及子类型的任何方法3: within(cn.javass.Secure *)持有 cn.javass.Secure注解的任何类型的任何方法必须是在目标对象上声明这个注解, 在接口上声明的对它不起作用切入点表达式的基本示例,使用 this使用“ this(类型全限定名)”匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口方法也可以匹配;注意this
15、中使用的表达式必须是类型全限定名,不支持通配符1: this(cn.javass.spring.chapter6.service.IPointcutService)当前AOP对象实现了 IPointcutService接口的任何方法2:this(cn.javass.spring.chapter6.service.I IntroductionService)当前AOP对象实现了 IIntroductionService接口的任何方法也可能是引入接口切入点表达式的基本示例,使用 target使用“target(类型全限定名)”匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引
16、入接口也类型匹配;注意 target 中使用的表达式必须是类型全限定 名,不支持通配符1:target(cn.javass.spring.chapter6.service.IPointcutService)当前目标对象(非 AOF对象)实现了 IPoi ntcutService接口的任何方法2:target(cn.javass.spring.chapter6.service.IIntroductionService)当前目标对象(非 AOF对象)实现了 IIntroductionService接口的任何方法不可能是引入接口切入点表达式的基本示例,使用 args使用“ args( 参数类型列表
17、) ”匹配当前执行的方法传入的参数为指定类型的执行方法;注意 是匹配传入的参数类型, 不是匹配方法签名的参数类型; 参数类型列表中的参数必须是类型 全限定名,通配符不支持; args 属于动态切入点,这种切入点开销非常大,非特殊情况最 好不要使用1: args (java.io.Serializable,.)任何一个以接受 “传入参数类型为 java.io.Serializable ” 开头, 且其后可跟任意个任意 类型的参数的方法执行, args 指定的参数类型是在运行时动态匹配的 切入点表达式的基本示例,使用 within使用“ within( 注解类型 ) ”匹配所以持有指定注解类型内的
18、方法;注解类型也必须是全限 定类型名1: within cn.javass.spring.chapter6.Secure) 任何目标对象对应的类型持有 Secure 注解的类方法;必须是在目标对象上声明这个注解, 在接口上声明的对它不起作用切入点表达式的基本示例,使用 target使用“ target( 注解类型 ) ”匹配当前目标对象类型的执行方法,其中目标对象持有指定的 注解;注解类型也必须是全限定类型名1: target (cn.javass.spring.chapter6.Secure) 任何目标对象持有 Secure 注解的类方法;必须是在目标对象上声明这个注解,在接口上声 明的对它
19、不起作用切入点表达式的基本示例,使用 args使用“ args(注解列表)”匹配当前执行的方法传入的参数持有指定注解的执行;注解类型 也必须是全限定类型名1: args (cn.javass.spring.chapter6.Secure) 任何一个只接受一个参数的方法,且方法运行时传入的参数持有注解 cn.javass.spring.chapter6.Secure ;动态切入点,类似于 arg 指示符; 切入点表达式的基本示例,使用 annotation使用“ annotation( 注解类型 )”匹配当前执行方法持有指定注解的方法;注解类型也必须 是全限定类型名1: annotation(c
20、n.javass.spring.chapter6.Secure )当前执行方法上持有注解 cn.javass.spring.chapter6.Secure将被匹配切入点表达式的基本示例,使用 bean使用“ bean(Bean id 或名字通配符)”匹配特定名称的Bean对象的执行方法;Spring AOP扩展的,在 AspectJ 中无相应概念1:bean(*Service)匹配所有以 Service 命名(id或name)结尾的Bean切入点表达式的基本示例,使用 reference pointcut引用其他命名切入点,只有 ApectJ风格支持,Schema风格不支持,如下所示:java
21、 代码: 查看复制到剪贴板打印 Pointcut(value=bean(*Service) /命名切入点 1命名切入点 2private void pointcut1() Pointcut(value=args(cn.javass.spring.chapter6.Secure) / private void pointcut2()Before(value = pointcut1() & pointcut2() /引用命名切入点public void referencePointcutTest1(JoinPoint jp) dump(pointcut1() & pointcut2(), jp);
22、声明通知通知是跟一个切入点表达式关联起来的, 并且在切入点匹配的方法执行之前或者之后或者之 前和之后运行。 切入点表达式可能是指向已命名的切入点的简单引用或者是一个已经声明 过的切入点表达式。前置通知( Before advice ) ,使用 Before 注解声明java 代码:查看复制到剪贴板打印Aspectpublic class BeforeExample Before(execution(* com.xyz.myapp.dao.*.*(.)public void doAccessCheck() / . 返回后通知( After returning advice) ,使用 AfterR
23、eturning注解声明后通知( After (finally) advice),使用 After 注解声明抛出后通知( After throwing advice) ,使用 AfterThrowing注解声明可以将抛出的异常绑定到通知的一个参数上 ,如下:java 代码:查看复制到剪贴板打印AfterThrowing(pointcut=com.xyz.myapp.SystemArchitecture.dataAccessOperation(), throwing=ex)public void doRecoveryActions(Exception ex) / .环绕通知( Around Ad
24、vice ) ,使用 Around 注解声明java 代码:查看复制到剪贴板打印Around(com.xyz.myapp.SystemArchitecture.businessService()public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable / start stopwatchObject retVal = ceed();/ stop stopwatchreturn retVal;给 Advice 传递参数通常情况下, Advice 都需要获取一定的参数, 比如: Before 需要截
25、获传入的参数, 而 After 需要获取方法的返回值等等。下面介绍两种方式方式一:使用 JoinPoint 来给 Advice 的方法传递参数Spring AOP提供使用org.aspectj.lang.JoinPoint类型获取连接点数据,任何通知方法的第一个参数都可以是 JoinPoint( 环绕通知是 ProceedingJoinPoint,JoinPoint 子类) ,当然第一个参数位置也可以是 JoinPoint.StaticPart 类型,这个只返回连接点的静态部分。1:JoinPoint :提供访问当前被通知方法的目标对象、代理对象、方法参数等数据java 代码:查看复制到剪贴板
26、打印public interface JoinPoint String toString(); /连接点所在位置的相关信息String toShortString(); /连接点所在位置的简短相关信息String toLongString(); /连接点所在位置的全部相关信息Object getThis(); / 返回 AOP代理对象Object getTarget(); /返回目标对象Object getArgs(); /返回被通知方法参数列表Signature getSignature(); /返回当前连接点签名SourceLocation getSourceLocation();/返回连
27、接点方法所在类文件中的位置String getKind(); / 连接点类型StaticPart getStaticPart(); /返回连接点静态部分2: ProceedingJoinPoint:用于环绕通知,使用 proceed() 方法来执行目标方法java 代码:查看复制到剪贴板打印public interface ProceedingJoinPoint extends JoinPoint public Object proceed() throws Throwable;public Object proceed(Object args) throws Throwable;3: Joi
28、nPoint.StaticPart:提供访问连接点的静态部分,如被通知方法签名、连接点类型java 代码:查看复制到剪贴板打印public interface StaticPart Signature getSignature(); /返回当前连接点签名String getKind(); / 连接点类型int getId(); / 唯一标识String toString(); /连接点所在位置的相关信息String toShortString(); /连接点所在位置的简短相关信息String toLongString(); /连接点所在位置的全部相关信息4:示例:使用如下方式在通知方法上声明,
29、必须是在第一个参数,然后使用jp.getArgs()就能获取到被通知方法参数:java 代码: 查看复制到剪贴板打印Before(value=execution(* sayBefore(*) public void before(JoinPoint jp) Before(value=execution(* sayBefore(*)public void before(JoinPoint.StaticPart jp) 方式二:使用 args 来给 Advice 的方法传递参数,示例如:java 代码: 查看复制到剪贴板打印 Before(value=execution(* test(*) & a
30、rgs(param), argNames=param) public void before1(String param) System.out.println(=param: + param);切入点表达式 execution(* test(*) & args(param) :( 1)首先 execution(* test(*) 匹配任何方法名为 test ,且有一个任何类型的参数;( 2)args(param) 将首先查找通知方法上同名的参数,并在方法执行时(运行时) 匹配传入的参数是使用该同名参数类型,即 java.lang.String ;如果匹配将把该被通知参数传递给 通知方法上同名
31、参数。参数匹配的策略1可以通过argNames”属性指定参数名,示例如:java 代码: 查看复制到剪贴板打印Before(value= args(param), argNames=param) /明确指定了public void before1(String param) System.out.println(=param: + param);2:如果第一个参数类型是 JoinPoint 、ProceedingJoinPoint或 JoinPoint.StaticPart 类型,应该从“ argNames”属性省略掉该参数名(可选,写上也对),这些类型对象会自动传 入的,但必须作为第一个参数
32、 。示例如:java 代码:查看复制到剪贴板打印Before(value= args(param), argNames=param) /明确指定了public void before1(JoinPoint jp, String param) System.out.println(=param: + param);3:如果“ class 文件中含有变量调试信息”, Spring 将可以使用这些方法签名中的参数名 来确定参数名,示例如下:java 代码: 查看复制到剪贴板打印 Before(value= args(param) /不需要 argNames 了public void before1(
33、JoinPoint jp, String param) System.out.println(=param: + param);4:如果没有“ class 文件中含有变量调试信息”,将尝试自己的参数匹配算法,如果发现 参数绑定有二义性将抛出 AmbiguousBindingException 异常;对于只有一个绑定变量的切入 点表达式,而通知方法只接受一个参数,说明绑定参数是明确的,从而能配对成功 ,示例 如下:Before(value= args(param)public void before1(JoinPoint jp, String param) System.out.println(
34、=param: + param); 5:以上策略失败将抛出 IllegalArgumentException 。 处理参数java 代码: 查看复制到剪贴板打印 Around(execution(List find*(.) & + com.xyz.SystemArchitecture.inDataAccessLayer() & + args(accountHolderNamePattern)public Object preProcessQueryPattern(ProceedingJoinPoint pjp, String accountHolderNamePattern)throws Th
35、rowable String newPattern = preProcess(accountHolderNamePattern);return ceed(new Object newPattern); 获取方法运行后的返回值java 代码:查看复制到剪贴板打印 AfterReturning( pointcut=com.xyz.myapp.SystemArchitecture.dataAccessOperation(), returning=retVal)public void doAccessCheck(Object retVal) / .Advice 执行的顺序 如果有多个通知
36、想要在同一连接点运行会发生什么? Spring AOP 的执行通知的顺序跟 AspectJ 的一样。 在“进入”连接点的情况下,最高优先级的通知会先执行(所以上面给 出的两个前置通知( before advice )中,优先级高的那个会先执行)。 在“退出”连接点 的情况下, 最高优先级的通知会最后执行。 只需要记住通知是按照定义的顺序来执行的就可 以了。当定义在 不同的 切面里的两个通知都需要在一个相同的连接点中运行,那么除非你指定, 否则执行的顺序是未知的。 你可以通过指定优先级来控制执行顺序。 在 Spring 中可以在切 面类中实现 org.springframework.core.O
37、rdered 接口做到这一点。 在两个切面中, Ordered.getValue() 方法返回值较低的那个有更高的优先级。java 代码: 查看复制到剪贴板打印 声明一个切面 : 声明一个切入点 : 在切面里面声明一个切入点和声明一个顶级的切入点非常类似:java 代码:查看复制到剪贴板打印当需要连接子表达式的时候,&在XML中用起来非常不方便,所以关键字and, or 和not 可以分别用来代替 &, | 和 !。java 代码:查看复制到剪贴板打印声明通知 Advice , Before Advice返回后通知( After returning advice )java 代码:查看复制到剪
38、贴板打印抛出异常后通知( After throwing advice ) 后通知( After (finally) advice ) Around 通知java 代码:查看复制到剪贴板打印 通知的参数,可以通过 arg-names 属性来实现java 代码:查看复制到剪贴板打印Advisor“advisors ”这个概念来自 Spring1.2 对AOP的支持,在 AspectJ中是没有等价的概念。advisor 就像一个小的自包含的切面,这个切面只有一个通知。java 代码:查看复制到剪贴板打印Spring AOP 还是完全用 AspectJ ?优先选用Spring的AOP因为它不是一个人在
39、战斗,Spring除了 AOP还有IOC,还有事务等其他功能。如果你需要通知 domain 对象或其它没有在 Spring 容器中 管理的任意对象,那么你需要使用 AspectJ 。Spring AOP 中使用 AspectJ 还是 XML?优先使用 AspectJ。XML风格有两个缺点。第一是它不能完全将需求实现的地方封装到一个位置。DRY原则中说系统中的每一项知识都必须具有单一、无歧义、权威的表示。当使用XML风格时,如何实现一个需求的知识被分割到支撑类的声明中以及XML配置文件中。当使用AspectJ风格时就只有一个单独的模块 -切面-信息被封装了起来。第二是XML风格同AspectJ风
40、格所能表达的内容相比有更多的限制:仅仅支持si nglet on 切面实例模型,并且不能在XML中组合命名连接点的声明。Spring AOP使用JDK动态代理或者 CGLIB来为目标对象创建代理。如果被代理的目标对象 实现了至少一个接口,则会使用JDK动态代理。所有该目标类型实现的接口都将被代理。若该目标对象没有实现任何接口,则创建一个CGLIB代理。如果你希望强制使用 CGLIB代理,(例如:希望代理目标对象的所有方法,而不只是实现自 接口的方法)那也可以。但是需要考虑以下问题 :1:无法通知( advise )Final 方法,因为他们不能被覆写。2:将 CGLIB 2 二进制发行包放在
41、classpath 下面, JDK 本身就提供了动态代理3:强制使用 CGLIB 代理需要将 的 proxy-target-class 属性设为 true: 4:当需要使用 CGLIB代理和AspectJ自动代理支持,请按照如下的方式设置 的 proxy-target-class 属性: 切入点的 APIorg.springframework.aop.Pointcut是最核心的接口,用来将 通知应用于特定的类和方法,完整的接口定义如下:java 代码:查看复制到剪贴板打印 public interface Pointcut ClassFilter getClassFilter();Method
42、Matcher getMethodMatcher();以及进行更细粒度的操作组如果 matches() 方法总是返1:将 Pointcut 接口分割成有利于重用类和方法匹配的两部分, 合(例如与另一个方法匹配实现进行“或操作”)。2: ClassFilter 接口用来将切入点限定在一个给定的类集合中。 回 true ,所有目标类都将被匹配: public interface ClassFilter boolean matches(Class clazz);3: MethodMatcher 接口通常更重要,完整的接口定义如下:java 代码:查看复制到剪贴板打印public interface
43、MethodMatcher boolean matches(Method m, Class targetClass);boolean isRuntime();boolean matches(Method m, Class targetClass, Object args);matches(Method, Class) 方法用来测试这个切入点是否匹配目标类的指定方法。这将在AOP代理被创建的时候执行, 这样可以避免在每次方法调用的时候都执行。 如果 matches(Method, Class ) 对于一个给定的方法返回 true ,并且 isRuntime() 也返回 true ,那么 matc
44、hes(Method, Class , Object) 将在每个方法调用的时候被调用。这使得切入点在通 知将被执行前可以查看传入到方法的参数。大多数 MethodMatcher 是静态的,这意味着 isRuntime() 方法返回 false 。在这种情况下, matches(Method, Class , Object) 永远不会被调用。静态切入点静态切入点基于方法和目标类进行切入点判断而不考虑方法的参数。 在多数情况下, 静态切 入点是高效的、最好的选择。 Spring 只在第一次调用方法时执行静态切入点:以后每次调 用这个方法时就不需要再执行。1:正则表达式切入点正则表达式是最常用的描述
45、静态切入点的方式,多数AOP框架都支持这种方式。org.springframework.aop.support.Perl5RegexpMethodPointcut是一个最基本的正则表达式切入点, 它使用 Perl 5 正则表达式语法。示例如下:java 代码:查看复制到剪贴板打印.*set.*.*absquatulate拦截 around 通知Spring里使用方法拦截的around通知兼容AOF联盟接口。实现 around通知的MethodInterceptor 应当实现下面的接口:java 代码:查看复制到剪贴板打印public interface MethodInterceptor ex
46、tends Interceptor Object invoke(MethodInvocation invocation) throws Throwable;提示:在 invok 方法里面不要忘记调用: ceed();前置通知java 代码:查看复制到剪贴板打印public interface MethodBeforeAdvice extends BeforeAdvice void before(Method m, Object args, Object target) throws Throwable;后置通知java 代码:查看复制到剪贴板打印public interface AfterReturningAdvice extends Advice void afterReturning(Object returnValue, Method m, Object args, Object target)throws Throwable;异常通知如果连接点抛出异常,异常通知( throws advice )将在连接点返回后被调用。 Spring 提 供类型检查的异常通知,这意味着 org.springframework.aop.ThrowsAdvice 接口不包含任 何方法:它只是一个标记接口用来标识 所给对象实现了一个或者多个
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025-2030智慧农业服务供应商行业市场供需环境分析及投资发展评估报告
- 乙酸酯及其衍生物装置扩建项目投资计划书
- 都安瑶族自治县2024-2025学年中考数学考试模拟冲刺卷含解析
- 2025年新签劳动合同书
- 企业战略合作合同协议2025
- 2025年新疆粮油品牌推广合同协议书
- 餐饮基础服务课件
- 餐饮培训老师知识分享会课件
- 2025年建筑漫游制作合同协议
- 社区插花艺术创新创业项目商业计划书
- 《水土保持工程施工监理规范》
- 《高中数学圆锥曲线基础与应用教学案例》
- 腱鞘炎病人的护理常规
- 意大利地理知识
- 竞聘医药经理述职报告
- 2025年四川里伍铜业股份有限公司招聘笔试参考题库含答案解析
- 《有机氟化工生产过程副产氢氟酸》
- 2023年北京地铁综控员题库第一册
- 化工厂装置知识培训课件
- 《电影场景构图》课件
- 《种鸡场卫生管理》课件
评论
0/150
提交评论