1. AOP

1.1 AOP介绍

1.1.1 什么是AOP

  • 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
  • AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码。如下图所示:
  • 经典应用:事务管理、性能监视、安全检查、缓存 、日志等。
  • Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码。
  • AspectJ是一个基于Java语言的AOP框架,从Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入。

1.1.2 AOP实现原理

  • aop底层将采用代理机制进行实现
  • 接口+实现类时:Spring采用JDK的动态代理Proxy
  • 只有实现类时:Spring采用cglib字节码增强。这种底层属于继承增强。

1.1.3 AOP术语【掌握】

  1. Target :目标类,需要被代理的类。本例中如:UserDao
  2. Joinpoint(连接点) :所谓连接点是指那些可能被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点。本例中如:UserDao的所有的方法
  3. PointCut 切入点 :所谓切入点是指我们要对哪些Joinpoint进行拦截,即已经被增强的连接点。例如:save()
  4. Advice :通知/增强,增强的代码。例如:checkPri()

    所谓通知是指拦截到Joinpoint之后所要做的事情就是通知,通知分为前置通知、后置通知、异常通知、最终通知、环绕通知(即切面要完成的功能)。
  5. Weaving(织入) :是指把通知/增强advice应用到目标对象target来创建新的代理对象proxy的过程。

    spring采用动态代理织入,而AspectJ采用编译期织入和类装在期织入。
  6. Proxy :代理类,一个类被AOP织入增强后,就产生一个结果代理类。
  7. Aspect(切面) : 是切入点Pointcut和通知Advice(引介)的结合。
  8. Introduction(引介) :引介是一种特殊的通知,在不修改类代码的前提下,Introduction 可以在运行期为类动态地添加一些方法或Field。

  • 小结:

    一个线是一个特殊的面。

    一个切入点和一个通知,组成成一个特殊的面。

    详解如图01:

    详解如图02:

1.2 AOP的底层实现(了解)

  • 动态代理

    • JDK动态代理:只能对实现了接口的类产生代理
    • Cglib动态代理(第三方代理技术):对没有实现接口的类产生代理对象,生成子类对象。
    • 代理知识点参考:https://www.cnblogs.com/itzhouq/p/proxy1.html

1.2.1 JDK动态代理

  • 准备工作:新建web项目,不需要导包

  • 代理对象UserDao

    package com.itzhouq.spring.demo1;
    
    public interface UserDao {
    public void save();
    public void update();
    public void find();
    public void delete();
    }
  • 实现类

    package com.itzhouq.spring.demo1;
    
    public class UserDaoImpl implements UserDao {
    
    	@Override
    public void save() {
    System.out.println("保存用户");
    } @Override
    public void update() {
    System.out.println("更新用户");
    } @Override
    public void find() {
    System.out.println("查找用户");
    } @Override
    public void delete() {
    System.out.println("删除用户");
    } }
  • 使用JDK产生UserDao的代理类

    package com.itzhouq.spring.demo1;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy; /*
    * 使用JDK动态代理对UserDao产生代理
    */
    public class JDKProxy implements InvocationHandler {
    // 将被增强的对象传递到代理总
    private UserDao userDao;
    public JDKProxy(UserDao userDao) {
    this.userDao = userDao;
    }
    /*
    * 产生UserDao代理的方法
    */
    public UserDao createProxy() {
    UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(
    userDao.getClass().getClassLoader(),
    userDao.getClass().getInterfaces(),
    this);
    return userDaoProxy;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // 判断方法名是不是save
    if("save".equals(method.getName())) {
    // 增强
    System.out.println("权限校验==============");
    return method.invoke(userDao, args); }
    return method.invoke(userDao, args);
    }
    }
  • 测试类

    package com.itzhouq.spring.demo1;
    
    import org.junit.Test;
    
    public class SpringDemo1 {
    
    	@Test
    //JDK动态代理
    public void test1() {
    UserDao userDao = new UserDaoImpl();
    // 创建代理
    UserDao proxy = new JDKProxy(userDao).createProxy();
    proxy.save();
    proxy.find();
    proxy.delete();
    proxy.update();
    //权限校验==============
    //保存用户
    //查找用户
    //删除用户
    //更新用户
    }
    }

1.2.2 Cglib动态代理

  • Cglib是第三方开源代码生成类库,动态添加类的属性和方法

  • cglib的运行原理:在运行时创建目标类的子类从而对目标类进行增强。

  • 因为Spring核心包中包含了cglib的包,所以引入Spring的4+2必备包就可以使用Cglib了

  • 目标类:没有实现接口

    package com.itzhouq.spring.demo2;
    
    public class CustomerDao {
    public void save() {
    System.out.println("保存客户");
    }
    public void update() {
    System.out.println("更新客户");
    }
    public void find() {
    System.out.println("查找客户");
    }
    public void delete() {
    System.out.println("删除客户");
    }
    }
  • Cglib代理类

    package com.itzhouq.spring.demo2;
    
    import java.lang.reflect.Method;
    
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy; /*
    * Cglib动态代理
    */
    public class CglibProxy implements MethodInterceptor { private CustomerDao customerDao; public CglibProxy(CustomerDao customerDao) {
    this.customerDao = customerDao;
    } // 使用Cglib产生代理的方法
    public CustomerDao createProxy() {
    // 1. 创建cglib的核心类对象
    Enhancer enhancer = new Enhancer();
    // 2. 设置父类
    enhancer.setSuperclass(customerDao.getClass());
    // 3. 设置回调(类似于InvocationHandler对象)
    enhancer.setCallback(this);
    // 4. 创建代理对象
    CustomerDao proxy = (CustomerDao) enhancer.create();
    return proxy;
    } @Override
    public Object intercept(Object proxy, Method method, Object[] arg, MethodProxy methodProxy)
    throws Throwable {
    // 判断方法是否为save
    if("save".equals(method.getName())) {
    // 增强
    System.out.println("权限校验========");
    return methodProxy.invokeSuper(proxy, arg);
    }
    return methodProxy.invokeSuper(proxy, arg);
    }
    }
  • 测试

    package com.itzhouq.spring.demo2;
    
    import org.junit.Test;
    
    public class SpringDemo2 {
    /*
    * cglib的测试
    */ @Test
    public void test1() {
    CustomerDao customerDao = new CustomerDao();
    CustomerDao proxy = new CglibProxy(customerDao).createProxy();
    proxy.save();
    proxy.find();
    proxy.update();
    proxy.delete();
    //权限校验========
    //保存客户
    //查找客户
    //更新客户
    //删除客户
    }
    }

1.2.3 总结

  • Spring在运行期,生成动态代理对象,不需要特殊的编译器。
  • Spring AOP的底层是通过JDK动态代理或者Cglib动态代理技术为目标bean执行横向织入的。
    • Spring会优先使用Spring使用JDK代理方式进行代理
    • 若目标对象没有实现任何接口,Spring容器会使用Cglib动态代理
  • 标记为final的方法不能被代理,因为无法进行覆盖
  • Cglib动态代理,是针对的目标类产生子类,所以目标类不能被final修饰。
  • Spring只支持方法连接点,不提供属性连接。

2. Spring的AOP的开发(AspectJ的XML方式)

2.1 Spring的AOP简介

  • AOP思想最早是由AOP联盟组织提出。Spring是使用这种思想最好的框架。
  • Spring的AOP有自己的实现方式(非常繁琐)。AspectJ是一个AOP框架,Spring引入AspectJ作为自身AOP的开发
  • Spring两种开发方式
    • Spring传统方式(弃用)。
    • Spring基于AspectJ的AOP开发方式(使用)。

2.2 AOP入门开发

2.2.1 准备工程和jar包

  • 除去基本的6个包,在web项目中添加aop开发的相关jar包

    • AOP联盟规范包:..\spring相关依赖包\spring-framework-3.0.2.RELEASE-dependencies\org.aopalliance\com.springsource.org.aopalliance\1.0.0\com.springsource.org.aopalliance-1.0.0.jar
    • AOP包:..\spring-framework-4.2.4.RELEASE-dist\spring-framework-4.2.4.RELEASE\libs\spring-aop-4.2.4.RELEASE.jar
    • AspectJ包:..\spring相关依赖包\spring-framework-3.0.2.RELEASE-dependencies\org.aspectj\com.springsource.org.aspectj.weaver\1.6.8.RELEASE\com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
    • Spring和ASpectJ整合包:..\spring-framework-4.2.4.RELEASE-dist\spring-framework-4.2.4.RELEASE\libs\spring-aspects-4.2.4.RELEASE.jar
    • Spring整合JUnit单元测试包:..\spring-framework-4.2.4.RELEASE-dist\spring-framework-4.2.4.RELEASE\libs\spring-test-4.2.4.RELEASE.jar

2.2.2 引入Spring的配置文件

  • 引入aop的约束
  • 约束的位置:../spring-framework-4.2.4.RELEASE-dist/spring-framework-4.2.4.RELEASE/docs/spring-framework-reference/html/xsd-configuration.html 40.2.7 the aop schema
<?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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>

2.2.3 编写目标类并完成配置

  • 目标接口

    package com.itzhouq.spring.demo3;
    
    public interface ProductDao {
    public void save();
    public void update();
    public void find();
    public void delete();
    }
  • 目标类

    package com.itzhouq.spring.demo3;
    
    public class ProductDaoImpl implements ProductDao {
    
    	@Override
    public void save() {
    System.out.println("保存商品");
    } @Override
    public void update() {
    System.out.println("更新商品");
    } @Override
    public void find() {
    System.out.println("查找商品");
    } @Override
    public void delete() {
    System.out.println("删除商品");
    } }
  • 配置目标对象

    <!-- 配置目标对象:被增强的对象 -->
    <bean id="productDao" class="com.itzhouq.spring.demo3.ProductDaoImpl"></bean>

2.2.4 测试类

package com.itzhouq.spring.demo3;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /*
* AOP入门
*/
@RunWith(SpringJUnit4ClassRunner.class) //这两个注释就是Spring整合了JUnit单元测试
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo3 { //注入productDao
@Resource(name="productDao")
private ProductDao productDao; @Test
public void test1() {
productDao.save();
productDao.update();
productDao.find();
productDao.delete();
// 保存商品
// 更新商品
// 查找商品
// 删除商品
}
}
  • 下面需要对save()方法增强

2.2.5 编写一个切面类

  • 切面:多个通知和多个切入点的组合。

    package com.itzhouq.spring.demo3;
    /*
    * 切面类
    */
    public class MyAspectXML {
    public void checkPri() {
    System.out.println("权限校验。。。");
    }
    }

2.2.6 将切面类交给Spring

  • 	<!-- 将切面类交给Spring管理 -->
    <bean id="myAspect" class="com.itzhouq.spring.demo3.MyAspectXML"></bean>

2.2.7 通过AOP的配置实现动态代理

<!-- 通过AOP的配置完成对目标类产生代理 -->
<aop:config>
<!-- 表达式配置哪些类的哪些方法需要进行增强 -->
<aop:pointcut expression="execution(* com.itzhouq.spring.demo3.ProductDaoImpl.save(..))" id="pointcut1"/>
<!-- 配置切面 -->
<aop:aspect ref="myAspect">
<aop:before method="checkPri" pointcut-ref="pointcust1"/>
</aop:aspect>
</aop:config>

2.2.8 测试类中运行结果,save实现了增强

@RunWith(SpringJUnit4ClassRunner.class)	//这两个注释就是Spring整合了JUnit单元测试
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringDemo3 { //注入productDao
@Resource(name="productDao")
private ProductDao productDao; @Test
public void test1() {
productDao.save();
productDao.update();
productDao.find();
productDao.delete();
// 权限校验。。。
// 保存商品
// 更新商品
// 查找商品
// 删除商品 }
}

2.3 Spring中的通知类型

2.3.1 前置通知

  • 配置

    <!-- 配置切面 -->
    <aop:aspect ref="myAspect">
    <aop:before method="checkPri" pointcut-ref="pointcut1"/>
    </aop:aspect>
  • 在目标方法执行之前进行操作

  • 可以获得切入点的信息

  • 比如在切面类中加入参数JoinPoint

    public class MyAspectXML {
    
    	public void checkPri(JoinPoint joinPoint) {
    System.out.println("权限校验。。。"+joinPoint);
    }
    }

    测试打印的效果

    //		权限校验。。。execution(void com.itzhouq.spring.demo3.ProductDao.save())
    // 保存商品
    // 更新商品
    // 查找商品
    // 删除商品

2.3.2 后置通知:

  • 在目标方法之后操作,可以获得返回值

  • 修改接口ProductDao和实现类ProductDaoImpl类的delete方法的返回值为String

  • 配置后置通知

    <!-- 通过AOP的配置完成对目标类产生代理 -->
    <aop:config>
    <!-- 表达式配置哪些类的哪些方法需要进行增强 -->
    <aop:pointcut expression="execution(* com.itzhouq.spring.demo3.ProductDaoImpl.save(..))" id="pointcut1"/>
    <aop:pointcut expression="execution(* com.itzhouq.spring.demo3.ProductDaoImpl.delete(..))" id="pointcut2"/>
    <!-- 配置切面 -->
    <aop:aspect ref="myAspect">
    <!-- 前置通知============= -->
    <aop:before method="checkPri" pointcut-ref="pointcut1"/>
    <!-- 后置通知============= -->
    <aop:after-returning method="writeLog" pointcut-ref="pointcut2" returning="result"/>
    </aop:aspect>
    </aop:config>
  • 在后置切面类中添加记录日志的方法

    /*
    * 后置通知演示
    */
    public void writeLog(Object result) {
    System.out.println("日志记录======="+result);
    }
  • 测试

    权限校验。。。execution(void com.itzhouq.spring.demo3.ProductDao.save())
    // 保存商品
    // 更新商品
    // 查找商品
    // 删除商品
    // 日志记录=======kkk

2.3.3 环绕通知:

  • 在目标方法执行之前 和之后进行操作

  • 环绕通知可以组织目标方法的执行

  • 举例:需求---在修改方法update前后添加性能监控

  • 在切面类中添加一个方法用来测试环绕通知

    /**
    * 性能监控
    * @throws Throwable
    */
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("环绕前通知===========");
    Object obj = joinPoint.proceed();//这一步相当于执行目标程序
    System.out.println("环绕后通知=========");
    return obj;
    }
  • 配置环绕通知

    <aop:config>
    <!-- 表达式配置哪些类的哪些方法需要进行增强 -->
    <aop:pointcut expression="execution(* com.itzhouq.spring.demo3.ProductDaoImpl.save(..))" id="pointcut1"/>
    <aop:pointcut expression="execution(* com.itzhouq.spring.demo3.ProductDaoImpl.delete(..))" id="pointcut2"/>
    <aop:pointcut expression="execution(* com.itzhouq.spring.demo3.ProductDaoImpl.update(..))" id="pointcut3"/>
    <!-- 配置切面 -->
    <aop:aspect ref="myAspect">
    <!-- 前置通知============= -->
    <aop:before method="checkPri" pointcut-ref="pointcut1"/>
    <!-- 后置通知============= -->
    <aop:after-returning method="writeLog" pointcut-ref="pointcut2" returning="result"/>
    <!-- 环绕通知 -->
    <aop:around method="around" pointcut-ref="pointcut3"/>
    </aop:aspect>
    </aop:config>
  • 测试

    //		权限校验。。。execution(void com.itzhouq.spring.demo3.ProductDao.save())
    // 保存商品
    // 环绕前通知===========
    // 更新商品
    // 环绕后通知=========
    // 查找商品
    // 删除商品
    // 日志记录=======kkk

2.3.4 异常抛出通知:

  • 在程序抛出异常时候进行操作,可以得到异常信息

  • 在find方法上模拟一个异常

    @Override
    public void find() {
    System.out.println("查找商品");
    int i = 1 / 0;
    }
  • 切面类中添加一个方法用于测试异常抛出通知

    /*
    * 异常抛出通知
    */
    public void afterThrowing(Throwable ex) {
    System.out.println("异常抛出通知=======" + ex);
    }
  • 配置异常通知

    <aop:config>
    <!-- 表达式配置哪些类的哪些方法需要进行增强 -->
    <aop:pointcut expression="execution(* com.itzhouq.spring.demo3.ProductDaoImpl.save(..))" id="pointcut1"/>
    <aop:pointcut expression="execution(* com.itzhouq.spring.demo3.ProductDaoImpl.delete(..))" id="pointcut2"/>
    <aop:pointcut expression="execution(* com.itzhouq.spring.demo3.ProductDaoImpl.update(..))" id="pointcut3"/>
    <aop:pointcut expression="execution(* com.itzhouq.spring.demo3.ProductDaoImpl.find(..))" id="pointcut4"/>
    <!-- 配置切面 -->
    <aop:aspect ref="myAspect">
    <!-- 前置通知============= -->
    <aop:before method="checkPri" pointcut-ref="pointcut1"/>
    <!-- 后置通知============= -->
    <aop:after-returning method="writeLog" pointcut-ref="pointcut2" returning="result"/>
    <!-- 环绕通知 -->
    <aop:around method="around" pointcut-ref="pointcut3"/>
    <!-- 异常抛出通知 -->
    <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="ex"/>
    </aop:aspect>
    </aop:config>
  • 测试

    //		权限校验。。。execution(void com.itzhouq.spring.demo3.ProductDao.save())
    // 保存商品
    // 环绕前通知===========
    // 更新商品
    // 环绕后通知=========
    // 查找商品
    // 异常抛出通知=======java.lang.ArithmeticException: / by zero

2.3.5 最终通知:

  • 在切面类中添加方法测试最终通知

    /*
    * 最终通知:相当于finally代码块中的内容
    */
    public void after() {
    System.out.println("最终通知=========");
    }
  • 配置最终通知

    <!-- 配置最终通知 -->
    <aop:after method="after" pointcut-ref="pointcut4"/>
  • 测试

  • 无论是否有异常,最终通知都会执行。

2.3.6 引介通知(不用会)

2.4 切入点表达式【掌握】

1.execution()  用于描述方法【掌握】
语法:execution(修饰符 返回值 包.类.方法名(参数) throws异常)
修饰符,一般省略
public 公共方法
* 任意
返回值,不能省略
void 返回没有值
String 返回值字符串
* 任意
包,[可以省略]
com.itheima.crm 固定的包
com.itheima.crm.*.service crm包下面的任意子包,固定目录service(例如:com.itheima.crm.staff.service)
com.itheima.crm.. crm包下面的所有子包(含自己)
com.itheima.crm.*.service.. crm包下面的任意子包,固定目录service,service目录任意包(含自己)
类,[可以省略]
UserServiceImpl 指定的类
*Impl 以Impl结尾的类
User* 以User开头的类
* 任意的类
方法名,不能省略
addUser 固定的方法名
add* 以add开头的方法名
*Do 以Do结尾的方法名
* 任意的方法名
(参数)
() 无参
(int) 一个整型
(int, int) 两个整型
(..) 参数任意
throws,[可以省略],一般省略。 综合案例1:
execution(* com.itheima.crm.*.service..*.*(..))
综合案例2:
<aop:pointcut expression="execution(* com.itheima.*WithCommit.*(..)) ||
execution(* com.itheima.*Service.*(..))" id="myPointCut"/> 2.within:匹配包或子包中的方法(了解)
within(com.itheima.aop..*)
3.this:匹配实现了接口的代理对象中的方法(了解)
this(com.itheima.aop.user.UserDAO)
4.target:匹配实现了接口的目标对象中的方法(了解)
target(com.itheima.aop.user.UserDAO)
5.args:匹配参数格式符合标准的方法(了解)
args(int, int)
6.bean(id):对指定的bean所有的方法(了解)
bean('userServiceId')

Spring笔记03_AOP的更多相关文章

  1. Spring笔记02_注解_IOC

    目录 Spring笔记02 1. Spring整合连接池 1.1 Spring整合C3P0 1.2 Spring整合DBCP 1.3 最终版 2. 基于注解的IOC配置 2.1 导包 2.2 配置文件 ...

  2. Spring笔记01_下载_概述_监听器

    目录 Spring笔记01 1.Spring介绍 1.1 Spring概述 1.2 Spring好处 1.3 Spring结构体系 1.4 在项目中的架构 1.5 程序的耦合和解耦 2. Spring ...

  3. Spring 笔记 -06- 从 MySQL 建库到 登录验证数据库信息(maven)

    Spring 笔记 -06- 从 MySQL 建库到 登录验证数据库信息(maven) 本篇和 Spring 没有什么关系,只是学习 Spring,必备一些知识,所以放在这里了. 本篇内容: (1)M ...

  4. Spring笔记:事务管理

    Spring笔记:事务管理 事务管理 Spring事务管理是通过SpringAOP去实现的.默认情况下Spring在执行方法抛出异常后,引发事务回顾,当然你可以用拦截器或者配置去改变它们. 这部门内容 ...

  5. Spring笔记:AOP基础

    Spring笔记:AOP基础 AOP 引入AOP 面向对象的开发过程中,我们对软件开发进行抽象.分割成各个模块或对象.例如,我们对API抽象成三个模块,Controller.Service.Comma ...

  6. Spring:笔记整理(1)——HelloWorld

    Spring:笔记整理(1)——HelloWorld 导入JAR包: 核心Jar包 Jar包解释 Spring-core 这个jar 文件包含Spring 框架基本的核心工具类.Spring 其它组件 ...

  7. Spring笔记:IOC基础

    Spring笔记:IOC基础 引入IOC 在Java基础中,我们往往使用常见关键字来完成服务对象的创建.举个例子我们有很多U盘,有金士顿的(KingstonUSBDisk)的.闪迪的(SanUSBDi ...

  8. Spring笔记(6) - Spring的BeanFactoryPostProcessor探究

    一.背景 在说BeanFactoryPostProcessor之前,先来说下BeanPostProcessor,在前文Spring笔记(2) - 生命周期/属性赋值/自动装配及部分源码解析中讲解了Be ...

  9. spring笔记----看书笔记

    上周末看了一章以前javaee轻量级的书spring部分,简单做了一些笔记 // ApplicationContext ac=new ClassPathXmlApplicationContext(&q ...

随机推荐

  1. CSS Sprite雪碧图

    为了减少http请求数量,加速网页内容显示,很多网站的导航栏图标.登录框图片等,使用的并不是<image>标签,而是CSS Sprite雪碧图. 两个小例子: 淘宝首页的侧栏图 代码 &l ...

  2. Update API

    Update API可以根据提供的脚本更新文档. 该操作从索引获取文档,运行脚本(脚本语言和参数是可选的),并返回操作的结果(也允许删除或忽略该操作). 使用版本控制来确保在“get”(查询文档)和“ ...

  3. Ajax实现聊天室

    Ajax实现聊天室 运行效果如下: 代码显示: var net=new Object();//编写构造函数net.AjaxRequest=function(url,onload,onerror,met ...

  4. svn错误:更新源码出现校验和不匹配问题

    svn 的文本校验和不匹配: 最近在更新自动化源代码的时候出现了一个错误:svn: Checksum mismatch while updating.... 查了下google,原来是在更新源码出现校 ...

  5. 【RL-TCPnet网络教程】第37章 RL-TCPnet之FTP客户端

    第37章      RL-TCPnet之FTP客户端 本章节为大家讲解RL-TCPnet的FTP客户端应用,学习本章节前,务必要优先学习第35章的FTP基础知识.有了这些基础知识之后,再搞本章节会有事 ...

  6. [Swift]LeetCode20. 有效的括号 | Valid Parentheses

    Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the inpu ...

  7. [Swift]LeetCode287. 寻找重复数 | Find the Duplicate Number

    Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), pro ...

  8. [Swift]LeetCode770. 基本计算器 IV | Basic Calculator IV

    Given an expression such as expression = "e + 8 - a + 5" and an evaluation map such as {&q ...

  9. 优化之XML组件

    可在XML Parser 组件和XML Source定义中删除非project group,因为不需为这些非project group分配内存,但需要维护主键外键约束 ________________ ...

  10. 一个std::sort 自定义比较排序函数 crash的分析过程

    两年未写总结博客,今天先来练练手,总结最近遇到的一个crash case. 注意:以下的分析都基于GCC4.4.6 一.解决crash 我们有一个复杂的排序,涉及到很多个因子,使用自定义排序函数的st ...