SpringAOP03 项目脚手架、自定义注解、织入切面、引介增强
1 项目脚手架
利用 Maven 进行创建
1.1 利用IDEA创建一个Maven原型项目
技巧01:原型Maven项目是没有webapp文件夹和resources项目文件夹的,需要自己手动创建;创建完后需要进行模块配置 file -> project structure -> modules
1.2 配置 pom.xml 文件
需要引入一些 spring 和 aop 相关的依赖
<?xml version="1.0" encoding="UTF-8"?> <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>cn.xiangxu.com</groupId>
<artifactId>aop_base_demo</artifactId>
<version>1.0-SNAPSHOT</version> <name>aop_base_demo</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<file.encoding>UTF-8</file.encoding>
<spring.version>4.2.2.RELEASE</spring.version>
<testng.version>6.8.7</testng.version>
<asm.version>4.0</asm.version>
<cglib.version>3.0</cglib.version>
<aspectj.version>1.8.1</aspectj.version>
<aopalliance.version>1.0</aopalliance.version>
<commons-codec.version>1.9</commons-codec.version>
<slf4j.version>1.7.5</slf4j.version>
</properties> <dependencies>
<!-- spring 依赖-->
<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>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency> <!-- asm/cglib依赖(spring依赖) -->
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>${asm.version}</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-util</artifactId>
<version>${asm.version}</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>${cglib.version}</version>
<exclusions>
<exclusion>
<artifactId>asm</artifactId>
<groupId>org.ow2.asm</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>${aopalliance.version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec.version}</version>
</dependency> <dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.7.2</version>
<configuration>
<forkMode>once</forkMode>
<threadCount>10</threadCount>
<argLine>-Dfile.encoding=UTF-8</argLine>
</configuration>
</plugin>
</plugins>
</build> </project>
pom.xml
1.3 刷新maven下载相关依赖
技巧01:最好不要使用自带的maven仓库,使用自己修改过仓库地址的maven
2 自定义注解
2.1 利用 @interface 创建
技巧01:@Retention 用来指定注解有效范围,@Target 用来指定注解的使用范围
package cn.xiangxu.com.annotations; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface NeedTest {
boolean value() default true;
}
/*
* Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*/ package java.lang.annotation; /**
* Annotation retention policy. The constants of this enumerated type
* describe the various policies for retaining annotations. They are used
* in conjunction with the {@link Retention} meta-annotation type to specify
* how long annotations are to be retained.
*
* @author Joshua Bloch
* @since 1.5
*/
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE, /**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS, /**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
RetentionPolicy.java
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/ package java.lang.annotation; /**
* The constants of this enumerated type provide a simple classification of the
* syntactic locations where annotations may appear in a Java program. These
* constants are used in {@link Target java.lang.annotation.Target}
* meta-annotations to specify where it is legal to write annotations of a
* given type.
*
* <p>The syntactic locations where annotations may appear are split into
* <em>declaration contexts</em> , where annotations apply to declarations, and
* <em>type contexts</em> , where annotations apply to types used in
* declarations and expressions.
*
* <p>The constants {@link #ANNOTATION_TYPE} , {@link #CONSTRUCTOR} , {@link
* #FIELD} , {@link #LOCAL_VARIABLE} , {@link #METHOD} , {@link #PACKAGE} ,
* {@link #PARAMETER} , {@link #TYPE} , and {@link #TYPE_PARAMETER} correspond
* to the declaration contexts in JLS 9.6.4.1.
*
* <p>For example, an annotation whose type is meta-annotated with
* {@code @Target(ElementType.FIELD)} may only be written as a modifier for a
* field declaration.
*
* <p>The constant {@link #TYPE_USE} corresponds to the 15 type contexts in JLS
* 4.11, as well as to two declaration contexts: type declarations (including
* annotation type declarations) and type parameter declarations.
*
* <p>For example, an annotation whose type is meta-annotated with
* {@code @Target(ElementType.TYPE_USE)} may be written on the type of a field
* (or within the type of the field, if it is a nested, parameterized, or array
* type), and may also appear as a modifier for, say, a class declaration.
*
* <p>The {@code TYPE_USE} constant includes type declarations and type
* parameter declarations as a convenience for designers of type checkers which
* give semantics to annotation types. For example, if the annotation type
* {@code NonNull} is meta-annotated with
* {@code @Target(ElementType.TYPE_USE)}, then {@code @NonNull}
* {@code class C {...}} could be treated by a type checker as indicating that
* all variables of class {@code C} are non-null, while still allowing
* variables of other classes to be non-null or not non-null based on whether
* {@code @NonNull} appears at the variable's declaration.
*
* @author Joshua Bloch
* @since 1.5
* @jls 9.6.4.1 @Target
* @jls 4.1 The Kinds of Types and Values
*/
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE, /** Field declaration (includes enum constants) */
FIELD, /** Method declaration */
METHOD, /** Formal parameter declaration */
PARAMETER, /** Constructor declaration */
CONSTRUCTOR, /** Local variable declaration */
LOCAL_VARIABLE, /** Annotation type declaration */
ANNOTATION_TYPE, /** Package declaration */
PACKAGE, /**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER, /**
* Use of a type
*
* @since 1.8
*/
TYPE_USE
}
ElementType.java
2.2 使用注解
2.2.1 随便创建一个服务类
技巧01:在该服务类中的方法中使用自定义的注解即可
package cn.xiangxu.com.service; import cn.xiangxu.com.annotations.NeedTest;
import org.springframework.stereotype.Service; /**
* @author 王杨帅
* @create 2018-05-04 10:28
* @desc 自定义注解测试类
**/
@Service
public class AnnotationTestService {
@NeedTest
public void deleteUser(Integer userId) {
System.out.println("根据用户ID删除用户所有信息:" + userId);
} @NeedTest(value = false)
public void deleteUserAddress(String address) {
System.out.println("删除用户地址信息:" + address);
}
}
2.2.2 创建一个测试类
该测试类主要功能是获取注解对象信息
技巧01:getClass() 获取运行时的class信息,getDeclaredMethods() 获取已经声明的方法,getAnnotation 用来获取注解对象信息
package cn.xiangxu.com.service; import cn.xiangxu.com.annotations.NeedTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.Guice;
import org.testng.annotations.Test; import javax.annotation.Resource;
import java.lang.reflect.Method; import static org.testng.Assert.*; public class AnnotationTestServiceTest { @Test
public void tool() {
// 01 获取到AnnotationTestService对象
AnnotationTestService annotationTestService = new AnnotationTestService(); // 02 获取到AnnotationTestService中所有的Method数组
Method [] methods = annotationTestService.getClass().getDeclaredMethods();
System.out.println(methods.length); // 03 获取到方法上的注解信息
for (Method method : methods) {
NeedTest needTest = method.getAnnotation(NeedTest.class);
if (needTest != null) {
if (needTest.value()) {
System.out.println(method.getName() + "()需要进行单元测试");
} else{
System.out.println(method.getName() + "()不需要进行单元测试");
}
}
} } @Test
public void testDeleteUser() throws Exception {
} @Test
public void testDeleteUserAddress() throws Exception {
} }
AnnotationTestServiceTest.java
/**
* Returns the runtime class of this {@code Object}. The returned
* {@code Class} object is the object that is locked by {@code
* static synchronized} methods of the represented class.
*
* <p><b>The actual result type is {@code Class<? extends |X|>}
* where {@code |X|} is the erasure of the static type of the
* expression on which {@code getClass} is called.</b> For
* example, no cast is required in this code fragment:</p>
*
* <p>
* {@code Number n = 0; }<br>
* {@code Class<? extends Number> c = n.getClass(); }
* </p>
*
* @return The {@code Class} object that represents the runtime
* class of this object.
* @jls 15.8.2 Class Literals
*/
public final native Class<?> getClass();
getClass()
/**
*
* Returns an array containing {@code Method} objects reflecting all the
* declared methods of the class or interface represented by this {@code
* Class} object, including public, protected, default (package)
* access, and private methods, but excluding inherited methods.
*
* <p> If this {@code Class} object represents a type that has multiple
* declared methods with the same name and parameter types, but different
* return types, then the returned array has a {@code Method} object for
* each such method.
*
* <p> If this {@code Class} object represents a type that has a class
* initialization method {@code <clinit>}, then the returned array does
* <em>not</em> have a corresponding {@code Method} object.
*
* <p> If this {@code Class} object represents a class or interface with no
* declared methods, then the returned array has length 0.
*
* <p> If this {@code Class} object represents an array type, a primitive
* type, or void, then the returned array has length 0.
*
* <p> The elements in the returned array are not sorted and are not in any
* particular order.
*
* @return the array of {@code Method} objects representing all the
* declared methods of this class
* @throws SecurityException
* If a security manager, <i>s</i>, is present and any of the
* following conditions is met:
*
* <ul>
*
* <li> the caller's class loader is not the same as the
* class loader of this class and invocation of
* {@link SecurityManager#checkPermission
* s.checkPermission} method with
* {@code RuntimePermission("accessDeclaredMembers")}
* denies access to the declared methods within this class
*
* <li> the caller's class loader is not the same as or an
* ancestor of the class loader for the current class and
* invocation of {@link SecurityManager#checkPackageAccess
* s.checkPackageAccess()} denies access to the package
* of this class
*
* </ul>
*
* @jls 8.2 Class Members
* @jls 8.4 Method Declarations
* @since JDK1.1
*/
@CallerSensitive
public Method[] getDeclaredMethods() throws SecurityException {
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
return copyMethods(privateGetDeclaredMethods(false));
}
getDeclaredMethods()
/**
* {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @since 1.5
*/
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
return super.getAnnotation(annotationClass);
}
getAnnotation()
3 切面样例
3.1 创建所需的服务接口和服务类
说明:Waiter 是一个接口利用有两个方法,其中greetTo方法有@NeedTest注解;NaiveWaiter是Waiter接口的实现类
package cn.xiangxu.com.service; import cn.xiangxu.com.annotations.NeedTest; public interface Waiter {
@NeedTest
public void greetTo(String clientName);
public void serveTo(String clientName);
}
Waiter.java
package cn.xiangxu.com.service; public class NaiveWaiter implements Waiter {
public void greetTo(String clientName) {
System.out.println("NaiveWaiter:greet to "+clientName+"...");
}
public void serveTo(String clientName){
System.out.println("NaiveWaiter:serving "+clientName+"...");
}
public void smile(String clientName,int times){
System.out.println("NaiveWaiter:smile to "+clientName+ times+"times...");
}
}
NaiveWaiter.java
3.2 创建切面类
技巧01:一个完整的切面类必须包含: 切点、增强、横切逻辑
package cn.xiangxu.com.aops.example; import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before; /**
* @author 王杨帅
* @create 2018-05-04 11:09
* @desc
**/
@Aspect
public class PreGreetingAspect {
@Before("execution(* greetTo(..))")
public void beforeGreeting() {
System.out.println("How are you");
}
}
PreGreetingAspect.java
3.3 织入切面
3.3.1 通过编程方式
利用 AspectJProxyFactory 织如基于 @AspectJ注解的类
package cn.xiangxu.com.aops.example; import cn.xiangxu.com.service.NaiveWaiter;
import cn.xiangxu.com.service.Waiter;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test; import javax.annotation.Resource; import static org.testng.Assert.*; public class PreGreetingAspectTest {
@Test
public void testBeforeGreeting() throws Exception {
// 01 生成目标对象实例
Waiter target = new NaiveWaiter();
// 02 实例化工厂
AspectJProxyFactory factory = new AspectJProxyFactory();
// 03 设置目标对象
factory.setTarget(target);
// 04 添加切面类
factory.addAspect(PreGreetingAspect.class); // 05 生成植入切面的代理对象
Waiter proxy = factory.getProxy();
// 06 利用代理对象调用方法
proxy.greetTo("Warrior");
System.out.println("parting line");
proxy.serveTo("Warrior"); } }
PreGreetingAspectTest.java
3.3.2 利用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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<aop:aspectj-autoproxy/>
<!--bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/-->
<bean id="waiter" class="cn.xiangxu.com.service.NaiveWaiter" />
<bean class="cn.xiangxu.com.aops.example.PreGreetingAspect" />
</beans>
》测试类
package cn.xiangxu.com.aops.example; import cn.xiangxu.com.service.NaiveWaiter;
import cn.xiangxu.com.service.Waiter;
import javafx.application.Application;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test; import javax.annotation.Resource; import static org.testng.Assert.*; public class PreGreetingAspectTest { /**
* 利用 编码的方式织入切面
* @throws Exception
*/
@Test
public void testBeforeGreeting() throws Exception {
// 01 生成目标对象实例
Waiter target = new NaiveWaiter();
// 02 实例化工厂
AspectJProxyFactory factory = new AspectJProxyFactory();
// 03 设置目标对象
factory.setTarget(target);
// 04 添加切面类
factory.addAspect(PreGreetingAspect.class); // 05 生成植入切面的代理对象
Waiter proxy = factory.getProxy();
// 06 利用代理对象调用方法
proxy.greetTo("Warrior");
System.out.println("parting line");
proxy.serveTo("Warrior"); } /**
* 利用Spring配置的方式织入切面
*/
@Test
public void testBeforeGreeting02() {
// 01 配置文件路径
String configPath = "aops/example/beans.xml"; // 02 获取应用上下文
ApplicationContext ac = new ClassPathXmlApplicationContext(configPath); // 03 利用应用上下文获取对象
Waiter waiter = (Waiter)ac.getBean("waiter"); waiter.greetTo("fury");
System.out.println("===parting line===");
waiter.serveTo("warrior"); } }
PreGreetingAspectTest.java
4 引介增强
引介增强最主要的目的是为类A添加一个需要实现的接口B,并指定实现类C(解释:C是B的实现类);简而言之,类A可以通过引介增强来实现接口B,实现的方式是利用了类C
4.1 创建接口B
package cn.xiangxu.com.service; public interface Seller {
int sell(String goods, String clientName);
}
Seller.java
4.2 创建接口B的实现类C
package cn.xiangxu.com.service; public class SmartSeller implements Seller { public int sell(String goods,String clientName) {
System.out.println("SmartSeller: sell "+goods +" to "+clientName+"...");
return 100;
} public void checkBill(int billId){
if(billId == 1) throw new IllegalArgumentException("iae Exception");
else throw new RuntimeException("re Exception");
}
}
SmartSeller.java
4.3 创建切面类
该切面类主要实现引介增强
package cn.xiangxu.com.aops.basic; import cn.xiangxu.com.service.Seller;
import cn.xiangxu.com.service.SmartSeller;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents; @Aspect
public class EnableSellerAspect {
@DeclareParents(value="cn.xiangxu.com.service.NaiveWaiter",
defaultImpl=SmartSeller.class)
public Seller seller;
}
EnableSellerAspect.java
4.4 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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<aop:aspectj-autoproxy/>
<bean id="waiter" class="cn.xiangxu.com.service.NaiveWaiter"/>
<bean class="cn.xiangxu.com.aops.basic.EnableSellerAspect"/>
</beans>
4.5 编写测试类
package cn.xiangxu.com.aops.basic; import cn.xiangxu.com.service.Seller;
import cn.xiangxu.com.service.Waiter;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test; public class EnableSellerAspectTest { @Test
public void test01() {
// 01 配置文件路径
String configPath = "aops/basic/beans.xml";
// 02 实例化应用上下文
ApplicationContext ac = new ClassPathXmlApplicationContext(configPath);
// 03 获取bean对象
Waiter waiter = (Waiter)ac.getBean("waiter"); // 04 调用实例方法
waiter.greetTo("fury"); // 05 类型强转
Seller seller = (Seller)waiter;
seller.sell("hotpot", "王杨帅");
} }
EnableSellerAspectTest.java
5 本博文源代码
SpringAOP03 项目脚手架、自定义注解、织入切面、引介增强的更多相关文章
- 如何优雅地在 Spring Boot 中使用自定义注解,AOP 切面统一打印出入参日志 | 修订版
欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 资深架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...
- Spring Boot 自定义注解,AOP 切面统一打印出入参请求日志
其实,小哈在之前就出过一篇关于如何使用 AOP 切面统一打印请求日志的文章,那为什么还要再出一篇呢?没东西写了? 哈哈,当然不是!原因是当时的实现方案还是存在缺陷的,原因如下: 不够灵活,由于是以所有 ...
- SpringBoot 通过自定义注解实现AOP切面编程实例
一直心心念的想写一篇关于AOP切面实例的博文,拖更了许久之后,今天终于着手下笔将其完成. 基础概念 1.切面(Aspect) 首先要理解‘切’字,需要把对象想象成一个立方体,传统的面向对象变成思维,类 ...
- Spring Boot 中使用自定义注解,AOP 切面打印出入参日志及Dubbo链路追踪透传traceId
一.使用背景 开发排查系统问题用得最多的手段就是查看系统日志,在分布式环境中一般使用 ELK 来统一收集日志,但是在并发大时使用日志定位问题还是比较麻烦,由于大量的其他用户/其他线程的日志也一起输出穿 ...
- Java基于自定义注解的面向切面的实现
目的:实现在任何想要切的地方添加一个注解就能实现面向切面编程 自定义注解类 @Target({ElementType.PARAMETER, ElementType.METHOD}) @Retentio ...
- SpringBoot项目中自定义注解的使用
1.定义注解接口 @Documented @Retention(RUNTIME) @Target(METHOD) public @interface MyLog { String value() ...
- Spring自定义注解配置切面实现日志记录
一: spring-mvc.xml: <!--配置日志切面 start,必须与mvc配置在同一个配置文件,否则无法切入Controller层--><!-- 声明自动为spring容器 ...
- 框架源码系列三:手写Spring AOP(AOP分析、AOP概念学习、切面实现、织入实现)
一.AOP分析 问题1:AOP是什么? Aspect Oriented Programming 面向切面编程,在不改变类的代码的情况下,对类方法进行功能增强. 问题2:我们需要做什么? 在我们的框架中 ...
- Spring AOP 之编译期织入、装载期织入、运行时织入(转)
https://blog.csdn.net/wenbingoon/article/details/22888619 一 前言 AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP ...
随机推荐
- Python虚拟环境设置
Python2环境 首先,我们用pip安装virtualenv: pip3 install virtualenv 然后,假定我们要开发一个新的项目,需要一套独立的Python运行环境,可以这么做: 第 ...
- Cloudera Manager (centos)安装详细介绍
文章全部来自:Cloudera Manager (centos)安装详细介绍http://www.aboutyun.com/thread-9190-1-1.html(出处: about云开发) 这里已 ...
- 智能电视软件安装(WIFI上网)
智能电视软件上网(电视可连接无线网的称之为:智能电视) 1.安装当贝市场 链接:http://www.dangbei.com/ 2.安装电视家浏览器 链接:http://www.tvapk.net/f ...
- 实现一个scnprinf
#include <stdio.h> #include <stdarg.h> /* 该函数ret = min(size, 实际写入长度) - 1,即ret永远小于size * ...
- python操作rabbitmq操作数据(不错)
##一.RabbitMQ 消息队列介绍 RabbitMQ也是消息队列,那RabbitMQ和之前python的Queue有什么区别么? py 消息队列: 线程 queue(同一进程下线程之间进行交互) ...
- Pod Installing openssl-ios-bitcode报错
pod update --no-repo-update 问题:执行上面的操作之后,pod在安装ssl的时候会报错.部分报错信息如下: localhost:OpenSSLTest Later$ pod ...
- 选择排序的JavaScript实现
思想 原址比较的排序算法.即首先找到数结构中的最小值并将其放置在第一位,然后找到第二小的值将其放置在第二位...以此类推. 代码 function selectionSort(arr) { const ...
- mysql 执行批量的sql
<?xml version="1.0" encoding="utf-8" ?> <dbconfig> <!-- 数据库驱动 --& ...
- jvm是怎样调用方法的
jvm内部有五种调用方法的指令 invokeinterface 用以调用接口方法,在运行时搜索一个实现了这个接口方法的对象,找出适合的方法进行调用.(Invoke interface method) ...
- shell编程中用户输入处理(shell 04)
shell编程中用户输入处理1.命令行参数2.脚本运行时获取输入 命令行参数 通过空格来进行分割的位置参数 :$+position $0,$1,$2 ....$0 :程序名$1,$2,$3 ... $ ...