SSH框架之Spring第三篇
1.1 AOP概述
1.1.1 什么是AOP?
AOP : 全称是Aspect Oriented Progamming既 : 面向切面编程.通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.
简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强.
1.1.2 AOP的作用及优势
作用 :
在程序运行期间,不修改源码对已有方法进行增强.
优势 :
减少重复代码,提高开发效率,维护方便.
1.1.3 AOP的实现方式 : 使用动态代理技术
1.2.2.1 动态代理的特点 :
字节码随用随创建,随用随加载.
它与静态代理的区别也在于此.因为静态代理是字节码一上来就创建好,并完成加载.
装饰着模式就是静态代理的一种体现.
1.2.2.2 动态代理常用的有两种方式
基于接口的动态代理
提供者 : JDK官方的Proxy类.
要求 : 被代理来最少实现一个接口.
基于子类的动态代理
提供者 : 第三方的CGLib,如果报asmxxxx异常,需要导入asm.jar.
要求 : 被代理类不能用final修饰的类(最终类).
1.3 Spring中的AOP
1.3.1 关于代理的选择
在Spring中,框架根据目标类实现了接口决定采用哪种动态代理的方式.
1.3.2 AOP相关术语
Joinpoint(连接点) : 所谓连接点是指那些被拦截到的点.在Spring中,这些点值得是方法,因为spring只支持方法类型的连接点.
Pointcut(切入点) : 所谓切入点是指我们要对那些Joinpoint进行拦截的定义.
Advice(通知/增强) : 所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.
通知的类型 : 前置通知,后置通知,异常通知,最终通知,环绕通知.
Introduction(引介) : 是一种特殊的通知在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或Field.
Target(目的对象) :
代理的目标对象.
Weaving(织入) :
是值把增强应用到目标对象来创建新的代理对象的过程.
spring采用动态代理织入,而AspectJ采用编译器织入和类转载期织入.
Proxy (代理) :
一个类被AOP织入增强后,就是产生一个结果代理类.
Aspect(切面) :
是切入点和通知(引介) 的结合.
1.4 基于XML的AOP配置
1.4.1 导入包
1.4.2 准备接口
1.4.3 创建配置文件导入约束
<?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.1.4第四步:把客户的业务层配置到spring容器中
<!-- 把资源交给spring来管理 -->
<bean id="customerService" class="com.baidu.service.impl.CustomerServiceImpl"/>
2.1.5第五步:制作通知(增强的类)
/**
* 一个记录日志的工具类
*/
public class Logger {
/**
* 期望:此方法在业务核心方法执行之前,就记录日志
*/
public void beforePrintLog(){
System.out.println("Logger类中的printLog方法开始记录日志了。。。。");
}
}
2.2配置步骤
2.2.1第一步:把通知类用bean标签配置起来
<!-- 把有公共代码的类也让spring来管理(把通知类也交给spring来管理) -->
<bean id="logger" class="com.baidu.util.Logger"></bean>
2.2.2第二步:使用aop:config声明aop配置
<!-- aop的配置 -->
<aop:config>
<!-- 配置的代码都写在此处 -->
</aop:config>
2.2.3第三步:使用aop:aspect配置切面
<!-- 配置切面 :此标签要出现在aop:config内部
id:给切面提供一个唯一标识
ref:引用的是通知类的bean的id
-->
<aop:aspect id="logAdvice" ref="logger">
<!--配置通知的类型要写在此处-->
</aop:aspect>
2.2.4第四步:使用aop:before配置前置通知
<!-- 用于配置前置通知:指定增强的方法在切入点方法之前执行
method:用于指定通知类中的增强方法名称
ponitcut-ref:用于指定切入点的表达式的引用
-->
<aop:before method="beforePrintLog" pointcut-ref="pt1"/>
2.2.5第五步:使用aop:pointcut配置切入点表达式
<aop:pointcut expression="execution(public void com.baidu.service.impl.CustomerServiceImpl.saveCustomer())"
id="pt1"/>
2.3切入点表达式说明
execution:
匹配方法的执行(常用)
execution(表达式)
表达式语法:execution([修饰符] 返回值类型 包名.类名.方法名(参数))
写法说明:
全匹配方式:
public void com.baidu.service.impl.CustomerServiceImpl.saveCustomer()
访问修饰符可以省略
void com.baidu.service.impl.CustomerServiceImpl.saveCustomer()
返回值可以使用*号,表示任意返回值
* com.baidu.service.impl.CustomerServiceImpl.saveCustomer()
包名可以使用*号,表示任意包,但是有几级包,需要写几个*
* *.*.*.*.CustomerServiceImpl.saveCustomer()
使用..来表示当前包,及其子包
* com..CustomerServiceImpl.saveCustomer()
类名可以使用*号,表示任意类
* com..*.saveCustomer()
方法名可以使用*号,表示任意方法
* com..*.*()
参数列表可以使用*,表示参数可以是任意数据类型,但是必须有参数
* com..*.*(*)
参数列表可以使用..表示有无参数均可,有参数可以是任意类型
* com..*.*(..)
全通配方式:
* *..*.*(..) 2.4常用标签
2.4.1<aop:config>
作用:
用于声明开始aop的配置
2.4.2<aop:aspect>
作用:
用于配置切面。
属性:
id:给切面提供一个唯一标识。
ref:引用配置好的通知类bean的id。
2.4.3<aop:pointcut>
作用:
用于配置切入点表达式
属性:
expression:用于定义切入点表达式。
id:用于给切入点表达式提供一个唯一标识。
2.4.4<aop:before>
作用:
用于配置前置通知
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
2.4.5<aop:after-returning>
作用:
用于配置后置通知
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
2.4.6<aop:after-throwing>
作用:
用于配置异常通知
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
2.4.7<aop:after>
作用:
用于配置最终通知
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
2.4.8<aop:around>
作用:
用于配置环绕通知
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用
2.5通知的类型
2.5.1类型说明
<!-- 配置通知的类型
aop:before:
用于配置前置通知。前置通知的执行时间点:切入点方法执行之前执行
aop:after-returning:
用于配置后置通知。后置通知的执行时间点:切入点方法正常执行之后。它和异常通知只能有一个执行
aop:after-throwing
用于配置异常通知。异常通知的执行时间点:切入点方法执行产生异常后执行。它和后置通知只能执行一个。
aop:after
用于配置最终通知。最终通知的执行时间点:无论切入点方法执行时是否有异常,它都会在其后面执行。
aop:around
用于配置环绕通知。他和前面四个不一样,他不是用于指定通知方法何时执行的。
-->
<aop:before method="beforePrintLog" pointcut-ref="pt1"/>
<aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"/>
<aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"/>
<aop:after method="afterPrintLog" pointcut-ref="pt1"/>
<aop:around method="aroundPringLog" pointcut-ref="pt1"/>
2.5.2环绕通知的特殊说明
/**
* 环绕通知
* 它是spring框架为我们提供的一种可以在代码中手动控制增强部分什么时候执行的方式。
* 问题:
* 当我们配置了环绕通知之后,增强的代码执行了,业务核心方法没有执行。
* 分析:
* 通过动态代理我们知道在invoke方法中,有明确调用业务核心方法:method.invoke()。
* 我们配置的环绕通知中,没有明确调用业务核心方法。
* 解决:
* spring框架为我们提供了一个接口:ProceedingJoinPoint,它可以作为环绕通知的方法参数
* 在环绕通知执行时,spring框架会为我们提供该接口的实现类对象,我们直接使用就行。
* 该接口中有一个方法proceed(),此方法就相当于method.invoke()
*/
public void aroundPringLog(ProceedingJoinPoint pjp){
try {
System.out.println("前置通知:Logger类的aroundPringLog方法记录日志");
pjp.proceed();
System.out.println("后置通知:Logger类的aroundPringLog方法记录日志");
} catch (Throwable e) {
System.out.println("异常通知:Logger类的aroundPringLog方法记录日志");
e.printStackTrace();
}finally{
System.out.println("最终通知:Logger类的aroundPringLog方法记录日志");
}
}
3.1 基于注解的AOP配置
3.1.1 环境搭建 准备业务层和接口并用注解配置
3.1.2 导入jar包
3.1.3 创建spring的配置文件并导入约束
3.1.4 第四步:把资源使用注解让spring来管理
3.1.5 第五步 : 在配置文件中指定spring要扫描的包
<-- 告知spring,在创建容器时要扫描的包-->
<context:component-scan base-package="com.baidu"></context:component-scan> 3.2 配置步骤
3.2.1第一步:把通知类也使用注解配置
/**
* 一个记录日志的工具类
*/
@Component("logger")
public class Logger {
/**
* 期望:此方法在业务核心方法执行之前,就记录日志
* 前置通知
*/
public void beforePrintLog(){
System.out.println("前置通知:Logger类中的printLog方法开始记录日志了");
}
}
3.2.2第二步:在通知类上使用@Aspect注解声明为切面
/**
* 一个记录日志的工具类
*/
@Component("logger")
@Aspect//表明当前类是一个切面类
public class Logger {
/**
* 期望:此方法在业务核心方法执行之前,就记录日志
* 前置通知
*/
public void beforePrintLog(){
System.out.println("前置通知:Logger类中的printLog方法开始记录日志了");
}
}
3.2.3第三步:在增强的方法上使用@Before注解配置前置通知
/**
* 期望:此方法在业务核心方法执行之前,就记录日志
* 前置通知
*/
@Before("execution(* com.baidu.service.impl.*.*(..))")//表示前置通知
public void beforePrintLog(){
System.out.println("前置通知:Logger类中的printLog方法开始记录日志了");
}
3.2.4第四步:在spring配置文件中开启spring对注解AOP的支持
<!-- 开启spring对注解AOP的支持 -->
<aop:aspectj-autoproxy/>
3.3常用注解
3.3.1@Aspect:
作用:
把当前类声明为切面类。
3.3.2@Before:
作用:
把当前方法看成是前置通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。
3.3.3@AfterReturning
作用:
把当前方法看成是后置通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。
3.3.4@AfterThrowing
作用:
把当前方法看成是异常通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。
3.3.5@After
作用:
把当前方法看成是最终通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。
3.3.6@Around
作用:
把当前方法看成是环绕通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。
3.3.7@Pointcut
作用:
指定切入点表达式
属性:
value:指定表达式的内容
3.4不使用XML的配置方式
@Configuration
@ComponentScan(basePackages="com.baidu")
@EnableAspectJAutoProxy
public class SpringConfiguration {
}
总结 :
方法称为连接点.
切入点 : 具体对那个方法做增强.切入点的表达式.
Advice(通知/增强) : 对save方法做增强,编写程序增强要做的事情.
通知类型 : 前置通知,后置通知,最终通知,异常通知和环绕通知.
Target(目标对象) : UserServiceImpl对象
Proxy (代理) : 生成的代理对象
Aspect(切面) : 抽象的概念
切面 = 切入点 + 通知.
Weaving(织入) : 是指把增强应用到目标对象来创建新的代理对象的过程.
AOP配置文件开发步骤 :
1 : 导入jar包
2 : 编写切面类,编写通知的方法(自己来编写的)
3 : 配置切面类,进行IOC的管理
4 : 编写AOP的增强.
<aop:config>
<!--配置切面 = 切入点(表达式) + 通知 -->
<aop:aspect ref="myXmlAspect">
<!--选择通知的类型,前置通知-->
<aop:before method="log" pointcut="execution(public void com.baidu.demo1.UserServiceImpl.save())"/>
</aop:aspect>
</aop:config>
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.baidu.demo1"/> <!-- 开启注解AOP -->
<aop:aspectj-autoproxy/>
package com.baidu.demo1; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component; /**
* 注解方式的切面类
* 声明当前类是切面类
* @author Administrator
*/
@Component("myAnnoAspect")
@Aspect // 声明当前类是切面类 = 切入点表达式 + 通知类型
public class MyAnnoAspect { /**
* 通知方法
* 配置通知类型,注解的属性编写的是切入点的表达式
* 通知类型全部采用注解方式
* @Before 前置通知
* @AfterReturning 后置通知,目标对象方法执行成功
* @AfterThrowing 异常通知
* @After 最终通知
*/
// @Before(value="execution(public * com.baidu.demo1.*.save(..))")
// @AfterReturning(value="execution(public * com.baidu.demo1.*.save(..))")
// @AfterThrowing(value="execution(public * com.baidu.demo1.*.save(..))")
// @After(value="execution(public * com.baidu.demo1.*.save(..))")
public void log(){
System.out.println("记录日志...");
} /**
* 环绕通知
*/
// @Around(value="execution(public * com.baidu.demo1.*.save(..))")
@Around(value="MyAnnoAspect.fn()")
public void arond(ProceedingJoinPoint pp){
try {
System.out.println("记录日志...");
// 让目标对象方法执行
pp.proceed();
System.out.println("记录日志...");
} catch (Throwable e) {
e.printStackTrace();
}
} /**
* 定义切入点的表达式
*/
@Pointcut(value="execution(public * com.baidu.demo1.*.save(..))")
public void fn(){} } 基于子类的动态代理:
package com.baidu.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方式生成代理对象
* 不用实现接口
* @author Administrator
*/
public class MyCglibProxy { /**
* 获取到代理对象
* @return
*/
public static RoleServiceImpl getProxy(final RoleServiceImpl role){
Enhancer e = new Enhancer();
// 设置父类
e.setSuperclass(role.getClass());
// 设置回调函数
e.setCallback(new MethodInterceptor() { // 调用代理对象的方法,那么intercept方法就会执行
public Object intercept(Object arg0, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 让目标对象方法执行
Object invoke = methodProxy.invoke(role, args);
// 增强
System.out.println("记录日志...");
return invoke;
}
});
// 创建代理对象
Object proxy = e.create();
// 把代理对象返回
return (RoleServiceImpl) proxy;
} }
<?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"> <!-- 管理service -->
<bean id="userService" class="com.baidu.demo1.UserServiceImpl"/> <!-- 先配置切面类 -->
<bean id="myXmlAspect" class="com.baidu.demo1.MyXmlAspect"/> <!-- 配置AOP的增强
<aop:config>
-->
<!-- 配置切面 = 切入点 (表达式)+ 通知
<aop:aspect ref="myXmlAspect">
-->
<!-- 选择通知的类型,前置通知
<aop:before method="log" pointcut="execution(public void com.baidu.demo1.UserServiceImpl.save())"/>
</aop:aspect>
</aop:config>
--> <!-- 配置AOP的增强 -->
<aop:config>
<!-- 编写切入点的表达式 -->
<aop:pointcut expression="execution(public void com.baidu.demo1.UserServiceImpl.save())" id="pt"/>
<aop:aspect ref="myXmlAspect">
<aop:before method="log" pointcut-ref="pt"/>
</aop:aspect>
</aop:config> <!--
切入点的表达式:
execution() 固定写法
public 可以省略不写
void 方法的返回值,可以写 * 号
包结构 也可以 * 号,不能省略不写
UserServiceImpl 类,可以编写 * 号,常见的编写的写法:*ServiceImpl
方法 可以编写*号 save* saveUser saveDept
参数列表 编写.. 指的可变参数 需求:对项目中的service的save方法进行增强
execution(public * com.baidu.*.*ServiceImpl.3save*(..))
-->
<aop:config>
<!-- <aop:pointcut expression="execution(public void com.baidu.demo1.UserServiceImpl.update())" id="pt"/> -->
<!-- <aop:pointcut expression="execution(void com.baidu.demo1.UserServiceImpl.save())" id="pt"/> -->
<!-- <aop:pointcut expression="execution(* com.baidu.demo1.UserServiceImpl.save())" id="pt"/> -->
<!-- <aop:pointcut expression="execution(* com.baidu.*.UserServiceImpl.save())" id="pt"/> -->
<!-- <aop:pointcut expression="execution(* com.baidu.*.*ServiceImpl.save())" id="pt"/> -->
<!-- <aop:pointcut expression="execution(* com.baidu.*.*ServiceImpl.save*())" id="pt"/> -->
<aop:pointcut expression="execution(* com.baidu.*.*ServiceImpl.save*(..))" id="pt"/>
<aop:aspect ref="myXmlAspect">
<aop:before method="log" pointcut-ref="pt"/>
</aop:aspect>
</aop:config> <!-- 配置AOP的增强 -->
<aop:config>
<!-- 编写切入点的表达式 -->
<aop:pointcut expression="execution(public void com.baidu.demo1.UserServiceImpl.save())" id="pt"/>
<aop:aspect ref="myXmlAspect">
<!-- 前置通知
<aop:before method="log" pointcut-ref="pt"/>
-->
<!-- 后置通知:目标对象方法执行成功后,通知方法才执行
<aop:after-returning method="log" pointcut-ref="pt"/>
-->
<!-- 异常通知:目标对象方法出现异常后,通知执行
<aop:after-throwing method="log" pointcut-ref="pt"/>
-->
<!-- 最终通知:目标对象方法执行成功或失败,都会执行
<aop:after method="log" pointcut-ref="pt"/>
-->
<!-- 环绕通知:在目标对象方法执行前后去增强,问题,默认捕获目标对象的方法,手动让目标对象的方法执行 -->
<aop:around method="around" pointcut-ref="pt"/>
</aop:aspect>
</aop:config> </beans> 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; @RunWith(value=SpringJUnit4ClassRunner.class)
// @ContextConfiguration(value="classpath:applicationContext.xml") //入门案例
// @ContextConfiguration(value="classpath:applicationContext2.xml") // 切入点的表达式
@ContextConfiguration(value="classpath:applicationContext3.xml") // 通知类型
public class Demo1 { @Resource(name="userService")
private UserService userService; /**
* AOP的入门程序
*/
@Test
public void run1(){
userService.save();
} }
SSH框架之Spring第三篇的更多相关文章
- SSH框架之Spring第四篇
1.1 JdbcTemplate概述 : 它是spring框架中提供的一个对象,是对原始JdbcAPI对象的简单封装.spring框架为我们提供了很多的操作模板类. ORM持久化技术 模板类 JDBC ...
- SSH框架之Struts2第三篇
1.3相关知识点 : 1.3.1 OGNL的表达式 : 1.3.1.1 什么是OGNL OGNL是Object-Graph Navigation Language的编写,它是一种功能强大的表达式语言, ...
- SSH框架之Hibernate第三篇
1.1 多表关系分析和创建. 1.1.1 表关系分析和创建 表数据和表数据之间可以存在的关系? 一对多的关系 客户和联系人 建立关系原则: 在多的一方创建一个字段,这个字段作为外键指向一的一方的主键 ...
- Maven环境下搭建SSH框架之Spring整合Hibernate
© 版权声明:本文为博主原创文章,转载请注明出处 1.搭建环境 Spring:4.3.8.RELEASE Hibernate:5.1.7.Final MySQL:5.7.17 注意:其他版本在某些特性 ...
- spring第三篇
在昨天下午更新sprin第二篇中,叙述了将对象交给spring创建和管理,今天在spring第三篇中,主要写两个点一是spring的思想 二是spring中bean元素的属性配置. 1 spring思 ...
- Eclipse搭建SSH框架(Struts2+Spring+Hibernate)
见识少的我经过一天多的研究才知道,在MyEclipse中搭好的框架的配置文件和jar包是通用的.接下来——亮剑! 工具:Eclipse+Tomcat+Mysql 一.先在Eclipse中配置好Tomc ...
- SSH框架中spring的原理
在ssh项目中,是有明确分工的,spring的作用就相当于将struts和hibernate连接起来,是将两个没有关系的框架的特性,方法,action都放在spring的配置文件中使他们建立关系.取他 ...
- Spring第三篇【Core模块之对象依赖】
前言 在Spring的第二篇中主要讲解了Spring Core模块的使用IOC容器创建对象的问题,Spring Core模块主要是解决对象的创建和对象之间的依赖关系,因此本博文主要讲解如何使用IOC容 ...
- SSH框架之Spring+Struts2+Hibernate整合篇
回顾 -Hibernate框架 ORM: 对象关系映射.把数据库表和JavaBean通过映射的配置文件映射起来, 操作JavaBean对象,通过映射的配置文件生成SQL语句,自动执行.操作数据库. 1 ...
随机推荐
- 走近深度学习,认识MoXing:初识华为云ModelArts的王牌利器 — MoXing
[摘要] 本文为MoXing系列文章第一篇,主要介绍什么是MoXing,MoXing API的优势以及MoXing程序的基本结构. MoXing的概念 MoXing是华为云深度学习服务提供的网络模型开 ...
- 【nodejs原理&源码赏析(5)】net模块与通讯的实现
[摘要] Node.js net模块的原理及使用 示例代码托管在:http://www.github.com/dashnowords/blogs 一. net模块简介 net模块是nodejs通讯功能 ...
- Python之HTTP协议
HTTP协议,又称超文本传输协议,主要用于浏览器与服务器之间的通信. HTTP 协议的制作者是蒂姆·伯纳斯-李,1991年设计出来的,HTTP 协议设计之前目的是传输网页数据的,现在允许传输任意类型的 ...
- 【强化学习】DQN 算法改进
DQN 算法改进 (一)Dueling DQN Dueling DQN 是一种基于 DQN 的改进算法.主要突破点:利用模型结构将值函数表示成更加细致的形式,这使得模型能够拥有更好的表现.下面给出公式 ...
- [TimLinux] CPU 常见架构介绍
1. 简介 系统性能依赖硬件架构,CPU架构决定了硬件的布局.常见的CPU架构:SMP, NUMA, MPP. 2. SMP(对称多处理器) SMP:Symmetric Multiprocessing ...
- 洛谷 题解 P1025 【数的划分】
将n个小球放到k个盒子中的情况总数 = (a)至少有一个盒子只有一个小球的情况数 + (b)没有一个盒子只有一个小球的情况数 这样写出表达式: a.因为盒子不加区分,那么=情况数与"将n-1 ...
- Linux中Postfix反病毒和垃圾邮件(十)
amavisd-new amavisd-new呼叫器是一个连接MTA和内容检测工具(诸如病毒扫描工具和SpamAssassin)的高性能接口程序,使用perl语言写成.它一般通过SMTP.ESMTP或 ...
- vbs 脚本 获取机器名/IP/MAC
strComputer = "."strMesseage="" Set objWMIService = GetObject("winmgmts:{im ...
- java开发中常用的Liunx操作命令
查看所有端口的占用情况 netstat -nultp 其中State值为LISTEN则表示已经被占用 查看某个端口的占用情况: netstat -anp |grep 端口号 在liunx中启动tomc ...
- 为什么HashMap的加载因子是0.75?
说在前面 在HashMap中,默认创建的数组长度是16,也就是哈希桶个数为16,当添加key-value的时候,会先计算出他们的哈希值(h = hash),然后用return h & (l ...