1、基于注解的零配置方式

Aspect允许使用注解定义切面、切入点和增强处理,spring框架可以识别并根据这些注解来生成AOP代理。spring只是用了和AspectJ 5一样的注解,但并没有使用AspectJ的编译器或者织入器,底层依然使用的是spring AOP。

为了启用spring对@Aspect切面配置的支持,并保证spring容器中的目标bean被一个或多个切面自动增强,必须在spring配置文件中加入以下代码:

引入命名空间:xmlns:aop="http://www.springframework.org/schema/aop"

引入元素:

http://www.springframework.org/schema/aop 
           http://www.springframework.org/schema/aop/spring-aop-4.0.xsd

启用对@Aspect注解的支持:<aop:aspectj-autoproxy/>

如果不打算使用spring的XML Schema配置方式,则应该在spring配置文件中增加如下代码来启用@AspectJ的支持。

<!-- 完全不打算使用spring的xml schema配置方式使用spring AOP,即bean的注册也使用注解的形式。
应该加入如下代码 ,AnnotationAwareAspectJAutoProxyCreator是一个bean后处理器,该bean
后处理器将会为容器中的所有bean生成AOP代理
-->
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/> 

为了在spring应用中启动@AspectJ的支持,还需要在应用的类加载路径下增加两个AspectJ库:aspectjweaver.jar和aspectjrt.jar,除此之外,spring AOP还依赖aopalliance.jar。

2、定义切面bean

使用@Aspect注解切面bean。

3、定义切入点

1》切入点的定义包含两部分:

1>定义切入点表达式:指定与哪些方法匹配。切入点表达式使用@Pointcut注解标注。

2>定义名字和任意参数的方法签名:方法签名方法体通常为空,返回值必须为void。签名方法有访问控制符,如private只能是本切入面中使用该切入点,与Java的访问控制符意义差不多。

切入点的定义:

package com.lfy.aspect;

import org.aspectj.lang.annotation.Pointcut;

/**
* 切入点组合连接符有&&、||、!
* @author lfy
*
*/
public class PointcutUtil { //使用@Pointcut注解定义切入点,public控制着切入点的访问权限
@Pointcut("execution(int com.lfy.impl.HelloImpl.fourAdviceGetParamer(..))")
public void myPointcut() {}
}

使用举例:

@Before("execution(int com.lfy.impl.HelloImpl.fourAdviceGetParamer(..)) || PointcutUtil.myPointcut()")
public void authority(JoinPoint jp) { System.out.println("FourAdviceGetParamerAspect.Before模拟执行权限检查");
//返回被织入增强的目标方法
System.out.println("被织入的目标方法是: "+jp.getSignature().getName());
System.out.println("被织入的目标方法的参数: "+Arrays.toString(jp.getArgs()));
System.out.println("被织入增强处理的目标对象为: "+jp.getTarget());
System.out.println("<---------------->");
}

2》切入点指示符

定义切入点的时候,execution就是一个切入点指示符。spring AOP仅支持部分AspectJ的切入点指示符。spring AOP支持的切入点指示符有:

1>excution:用于匹配执行方法的连接点。其表达式格式如下。

excution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?),对各部分的解析如下。

modifiers-pattern:指定方法的修饰符,支持通配符,该部分可以省略。

ret-type-pattern:指定方法的返回值类型,支持通配符,可以使用“*”通配符来匹配所有的返回值类型。

declaring-type-pattern:指定方法所属的类,支持通配符,该部分可以省略。

name-pattern:指定匹配指定的方法名,支持通配符,可以使用“*”通配符来匹配所有方法。

param-pattern:指定方法声明中的形参列表,支持两个通配符,即“*”和“..”,其中“*”代表一个任意类型的参数,“..”代表0个或多个任意类型的参数。

throws-pattern:指定目标方法声明抛出的异常类型,支持通配符,该部分可以省略。

2>within:用于限定匹配特定类型的连接点,当使用spring AOP的时候,只匹配方法执行的连接点(spring AOP支持方法连接)。

//在com.lfy.bean包中的任意连接点
within(com.lfy.bean.*)
//在com.lfy.bean包或其子包中的任意连接点
within(com.lfy.bean..*)

 3>this:用于限定AOP代理必须是指定类型的实例,匹配该对象的所有连接点。当使用spring AOP的时候,只能匹配方法执行的连接点(spring AOP支持方法连接)。

//匹配实现了com.lfy.bean.Person接口的AOP代理的所有连接点
//在spring AOP中只是方法执行的连接点
this(com.lfy.bean.Person)

4>target:用于限定目标对象必须是指定类型的实例,匹配该对象的所有连接点。当使用spring AOP的时候,只能匹配方法执行的连接点(spring AOP支持方法连接)。

//匹配实现了com.lfy.bean.Person接口的目标对象的所有连接点
//在spring AOP中只是方法执行的连接点
target(com.lfy.bean.Person)

5>args:用于对连接点的参数类型和数量进行限制,要求参数类型和数量是指定的数量和类型的实例。当使用spring AOP的时候,只能匹配方法执行的连接点(spring AOP支持方法连接)。

//匹配只接受一个参数,且传入的参数类型是Serializable的所有连接点
//在spring AOP中只是方法执行的连接点
args(java.io.Serializable)

6>bean:spring AOP提供的限制只匹配指定bean实例内的连接点(spring AOP支持方法连接)。定义bean表达式时需要传入bean的id或name,表示只匹配该bean实例内的连接点,支持使用“*”通配符。

//匹配com.lfy.impl.Chinese bean实例内方法执行的连接点
bean(com.lfy.impl.Chinese)
//匹配名字以Impl结尾的bean实例内方法执行的连接点
bean(*impl)

3》组合切入点表达式

spring支持使用如下3个逻辑运算符来组合切入点表达式:

1>&&:要求连接点同时匹配两个切入点表达式,即切入点表达式做逻辑与。

2>||:连接点匹配任意一个表达式,即表达式逻辑或。

3>!:连接点不匹配指定的切入点表达式,即切入点表达式逻辑非。

    @Before("execution(int com.lfy.impl.HelloImpl.fourAdviceGetParamer(..)) || PointcutUtil.myPointcut()")
public void authority(JoinPoint jp) { System.out.println("FourAdviceGetParamerAspect.Before模拟执行权限检查");
//返回被织入增强的目标方法
System.out.println("被织入的目标方法是: "+jp.getSignature().getName());
System.out.println("被织入的目标方法的参数: "+Arrays.toString(jp.getArgs()));
System.out.println("被织入增强处理的目标对象为: "+jp.getTarget());
System.out.println("<---------------->");
}

4、定义增强处理

1》Before增强处理

使用@Before注解一个切面方法,该方法作为Before增强处理,可以指定一个value属性,value属性的值就是切入点(可以是一个已有的切入点,也可以是表达式)。Before增强处理在目标方法前执行,不会影响目标方法的执行,除非Before增强抛异常了,则会阻止目标方法的执行

    @Before("execution(int com.lfy.impl.HelloImpl.fourAdviceGetParamer(..)) || PointcutUtil.myPointcut()")
public void authority(JoinPoint jp) { System.out.println("FourAdviceGetParamerAspect.Before模拟执行权限检查");
//返回被织入增强的目标方法
System.out.println("被织入的目标方法是: "+jp.getSignature().getName());
System.out.println("被织入的目标方法的参数: "+Arrays.toString(jp.getArgs()));
System.out.println("被织入增强处理的目标对象为: "+jp.getTarget());
System.out.println("<---------------->");
}

2》AfterReturning增强处理

使用@AfterReturning注解一个切面方法,AfterReturning增强处理将在目标方法正常完成后被织入。可以访问到目标方法的返回值,但不可以修改目标方法的返回值。

/**
* 该注解可以指定pointcut/value,returning这两个常用的属性:<br>
* 1>>pointcut/value:用于指定切入点表达式,可以是已有的切入点,也
* 可以直接指定表达式。pointcut指定的值会覆盖value指定的值。<br>
* 2>>returning:指定一个形参名,用于表示增强处理方法中可定义与此同名
* 的形参,该形参可用于访问目标方法的返回值。除此之外,在增强处理方法上定义
* 的该形参(代表目标方法的返回值)指定的类型,将限制目标方法必须返回该类型
* 的值或没有返回值。
* @param rvt
* 匹配com.lfy.impl包下的所有类所有方法的执行作为切入点
* 声明rvt时指定的类型会限制目标方法必须返回指定类型的值或没有返回值
* 此处将rvt的类型声明为Object,意味着对目标方法的返回值不加限制,
* 即目标方法可以是void返回类型,也可以是Object的所有子类,即无限制
*/
@AfterReturning(returning="rvt",pointcut="execution(* com.lfy.impl.*.*(..))")
public void log(Object rvt) { System.out.println("AfterReturning获取目标方法返回值: "+rvt);
System.out.println("AfterReturning模拟记录日志功能...");
}

3》AfterThrowing增强处理

使用@AfterThrowing注解一个切面方法,AfterThrowing用于处理未处理的异常。

/**
*
* 该注解可以指定pointcut/value,returning这两个常用的属性:<br>
* 1>>pointcut/value:用于指定切入点表达式,可以是已有的切入点,也
* 可以直接指定表达式。pointcut指定的值会覆盖value指定的值。<br>
* 2>>returning:指定一个形参名,用于表示增强处理方法中可定义与此同名
* 的形参,该形参可用于访问目标方法抛出的异常。除此之外,在增强处理方法上定义
* 的该形参(代表目标方法抛出的异常)指定的类型,将限制目标方法必须抛出该类型
* 的异常。
* @param ex
* 匹配com.lfy.impl包下的所有类所有方法的抛异常作为切入点
* 声明ex时指定的类型会限制目标方法必须抛出指定类型的异常
* 此处将ex的类型声明为Throwable,意味着对目标方法抛出的异常不加限制。<br>
*
* @说明:该增强处理能够处理该异常,但不能完全处理该异常,异常还将在目标函数往父级
* 传递。catch异常捕获则是完全处理。<br>
*/
@AfterThrowing(throwing="ex",pointcut="execution(* com.lfy.impl.*.*(..))")
public void doRecoveryActions(Throwable ex) { System.out.println("AfterThrowing目标方法中抛出的异常:"+ex);
System.out.println("AfterThrowing模拟增强处理对异常的修复业务...");
}

4》After增强处理

使用@After注解切面方法

package com.lfy.aspect;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect; /**
* After增强处理
* @author lfy
* 与AfterReturning的区别:AfterReturning增强处理只有在目标方法成功完成后才会被织入,
* After增强处理无论目标方法如何结束(包括成功完成和遇到异常中止),它都会被织入。
* After需要处理正常返回和异常返回两种情况。After增强处理需要指定一个value属性,用于指定已
* 有的切入点,或者切入点表达式。
*/
@Aspect
public class AfterAspect { @After("execution(* com.lfy.impl.*.*(..))")
public void release() { System.out.println("After模拟方法结束后的释放资源...");
}
}

5》Around增强处理

使用@Around注解切面方法。Around的功能近似是Before增强处理和AfterReturning增强处理的总和,它既可以在目标方法前织入增强处理,也可以在执行目标方法后织入增强处理。

目标方法作为它的一个回调,不是必须的,也就是增强处理完全可以阻止目标方法的执行。

还可以修改目标方法的入参,或者改变目标方法执行后的返回值

它不是一个线程安全的增强处理,通常需要保证它在线程安全的环境下执行。

使用时指定的value值可以是一个已有的切入点,也可以是一个切入点表达式。

当定义一个Around增强处理方法时,该方法的第一个参数必须是ProceedingJoinPoint类型(至少包含一个参数),在增强处理方法体内,调用ProceedingJoinPoint参数的proceed()方法才会执行目标方法,proceed()相当于就是目标方法,proceed()方法没有被调用,则目标方法不会被执行。调用proceed()方法还可以传入一个Object[]对象作为参数,相当于给目标方法传递实参。

package com.lfy.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect; /**
* Around增强处理
* @author lfy
*
*/
@Aspect
public class AroundAspect { /**
*
* @return Object
* @throws Throwable
*
*/
@Around("execution(* com.lfy.impl.*.*(..))")
public Object processTx(ProceedingJoinPoint jp) throws Throwable { System.out.println("Around执行目标方法之前,模拟开始事务...");
//获取目标方法原始的调用参数
Object[] args=jp.getArgs();
if(args!=null&&args.length>1) {
//修改目标方法调用参数的第一个参数
args[0]="[增强的前缀]"+args[0];
}
//改变后的参数去执行目标方法,并保存目标方法执行后的返回值
Object rvt=jp.proceed(args);
System.out.println("Around执行目标方法之后,模拟结束事务...");
//如果rvt的类型是Integer,将rvt改为它的平方
if(rvt!=null&&rvt instanceof Integer) {
rvt=(Integer)rvt*(Integer)rvt;
}
return rvt;
}
}

传入的参数Object[]数组长度与目标方法所需要参数的个数不相等,或者类型不匹配,都会引发异常。为了能够获取目标方法的参数的个数和类型,需要增强处理方法能够访问目标方法的参数。

6》访问目标方法的参数

访问目标方法的参数,最简单的做法是定义增强处理方法第一个参数定义为JoinPoint类型(ProceedingJoinPoint继承于JoinPoint),当该增强处理方法被调用时,该JoinPoint参数就代表了织入增强处理的连接点,JonPoint包含了如下常用方法:

1>Object[] getArgs():返回执行目标方法的参数。

2>Signature getSignature():返回被增强的方法的相关信息。

3>Object getTarget():返回被织入增强处理的目标对象。

4>Object getThis():返回AOP框架为目标对象生成的代理对象。

举个例子:

FourAdviceGetParamerAspect.java

package com.lfy.aspect;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut; /**
* Around、Before、After、AfterReturning四种增强处理<br>
* 访问目标方法最简单的做法是定义增强处理方法时将第一个参数定义为JoinPoint类型,
* 当该增强处理方法被调用时,该JoinPoint参数就代表了织入增强处理的连接点。JoinPoint
* 提供了如下的常用访问方法:<br>
* 1>Objeact[] getArgs():返回目标方法的参数<br>
* 2>Signature getSignature():返回目标方法的相关信息<br>
* 3>Object getTarget():返回被增强处理的对象<br>
* 4>Object getThis():返回AOP框架为目标对象生成的代理对象。<br>
* 在这些方法中,只有Around增强处理中可以对目标方法的参数进行修改!<br>
* @author lfy
*
* 切入点组合连接符有&&、||、!
*/
@Aspect
public class FourAdviceGetParamerAspect { @Around("execution(int com.lfy.impl.HelloImpl.fourAdviceGetParamer(..)) || PointcutUtil.myPointcut()")
public Object processTx(ProceedingJoinPoint jp) throws Throwable { System.out.println("FourAdviceGetParamerAspect.Around执行目标方法之前,模拟开始事务...");
//获取目标方法原始的调用参数
Object[] args=jp.getArgs();
if(args!=null && args.length>0 && args[0].getClass() == String.class) {
//修改目标方法调用参数的第一个参数
args[0]="[增强的前缀]"+args[0];
}
//改变后的参数去执行目标方法,并保存目标方法执行后的返回值
Object rvt=jp.proceed(args);
System.out.println("FourAdviceGetParamerAspect.Around执行目标方法之后,模拟结束事务...");
System.out.println("<---------------->");
//如果rvt的类型是Integer,将rvt改为它的平方
if(rvt!=null&&rvt instanceof Integer) {
rvt=(Integer)rvt*(Integer)rvt;
}
return rvt;
} @Before("execution(int com.lfy.impl.HelloImpl.fourAdviceGetParamer(..)) || PointcutUtil.myPointcut()")
public void authority(JoinPoint jp) { System.out.println("FourAdviceGetParamerAspect.Before模拟执行权限检查");
//返回被织入增强的目标方法
System.out.println("被织入的目标方法是: "+jp.getSignature().getName());
System.out.println("被织入的目标方法的参数: "+Arrays.toString(jp.getArgs()));
System.out.println("被织入增强处理的目标对象为: "+jp.getTarget());
System.out.println("<---------------->");
} @After("execution(int com.lfy.impl.HelloImpl.fourAdviceGetParamer(..)) || PointcutUtil.myPointcut()")
public void release(JoinPoint jp) { System.out.println("FourAdviceGetParamerAspect.After模拟方法结束后的释放资源...");
//返回被织入增强的目标方法
System.out.println("被织入的目标方法是: "+jp.getSignature().getName());
System.out.println("被织入的目标方法的参数: "+Arrays.toString(jp.getArgs()));
System.out.println("被织入增强处理的目标对象为: "+jp.getTarget());
System.out.println("<---------------->");
} @AfterReturning(returning="rvt",pointcut="execution(int com.lfy.impl.HelloImpl.fourAdviceGetParamer(..)) || PointcutUtil.myPointcut()")
public void log(JoinPoint jp,Object rvt) { System.out.println("FourAdviceGetParamerAspect.AfterReturning获取目标方法返回值: "+rvt);
System.out.println("FourAdviceGetParamerAspect.AfterReturning模拟记录日志功能...");
//返回被织入增强的目标方法
System.out.println("被织入的目标方法是: "+jp.getSignature().getName());
System.out.println("被织入的目标方法的参数: "+Arrays.toString(jp.getArgs()));
System.out.println("被织入增强处理的目标对象为: "+jp.getTarget());
System.out.println("<---------------->");
}
}

PointcutUtil.java

package com.lfy.aspect;

import org.aspectj.lang.annotation.Pointcut;

/**
* 切入点组合连接符有&&、||、!
* @author lfy
*
*/
public class PointcutUtil { //使用@Pointcut注解定义切入点,public控制着切入点的访问权限
@Pointcut("execution(int com.lfy.impl.HelloImpl.fourAdviceGetParamer(..))")
public void myPointcut() {}
}

beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- spring配置文件的根元素,使用spring-beans-4.0.xsd语义约束 -->
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"> <!-- 指定自动搜索bean组件、自动搜索切面类 -->
<context:component-scan base-package="com.lfy.aspect,com.lfy.impl">
<context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
</context:component-scan> <!-- 或者不打算使用spring的xml schema配置方式,则应该在spring配置文件中增加如下片段
来启动@AspectJ的支持
<bean class="org.springframework.aop.aspectj.annotation.
AnnotationAwareAspectJAutoProxyCreator"/>
为了在spring应用中启动@AspectJ的支持,还需要在应用的类加载路径下增加两个AspectJ库:
aspectjweaver.jar和aspectjrt.jar,除此之外,spring AOP还依赖aopalliance.jar
-->
<!-- 启动@AspectJ支持 -->
<aop:aspectj-autoproxy/> <!-- 完全不打算使用spring的xml schema配置方式使用spring AOP,即bean的注册也使用注解的形式。
应该加入如下代码 ,AnnotationAwareAspectJAutoProxyCreator是一个bean后处理器,该bean
后处理器将会为容器中的所有bean生成AOP代理
-->
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
</beans>

HelloImpl.java

package com.lfy.impl;

import org.springframework.stereotype.Component;

import com.lfy.bean.Hello;

/**
* 被增强的目标类
* @author lfy
*
*/
@Component("hello")
public class HelloImpl implements Hello { @Override
public void foo() { System.out.println("执行Hello组件的foo()方法");
} @Override
public void addUser(String name, String pass) { System.out.println("执行Hello组件的addUser()添加用户: "+name+",pass为"+pass);
} @Override
public int addGroup(String groupName, int groupMemberNumber) { System.out.println("执行Hello组件的addGroup()添加群组: "+groupName);
if(groupMemberNumber<0||groupMemberNumber>100) {
throw new IllegalArgumentException("群组成员数在0~100之间");
}
return 0;
} @Override
public int fourAdviceGetParamer(String param) { System.out.println("执行Hello组件的fourAdviceGetParamer()方法,param:"+param);
return 5;
} }

SpringAOPTest.java

package com.lfy.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import com.lfy.bean.Hello; /**
* 1、基于注解的“零配置”方式,演示获取切入点信息
* @author lfy
* 未登记的知识点:
* 1>指定增强处理的优先级,@Order注解及Orderd接口
* 2>切入点指示符
*/
public class SpringAOPTest { public static void main(String[] args) { ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
Hello hello=ctx.getBean("hello", Hello.class);
hello.addUser("孙悟空", "7788");
System.out.println("****************\n");
System.out.println("fourAdviceGetParamer默认只返回5,经过平方后:"+hello.fourAdviceGetParamer("唐僧"));
} }

运行结果:各方法内成功的获取到了切入点相关信息。Around增强处理修改了目标方法的入参、返回值,其实也只有Around增强可以修改并生效(影响)到目标方法。

7》如果只需要访问目标方法的参数

可以在程序中用args切入点表达式来绑定目标方法的参数。如果一个args表达式中指定了一个或多个参数,则该切入点将只匹配具有对应形参的方法(包括参数个数以及参数类型),且目标方法的参数值将被传入增强处理方法。

@AfterReturning(returning="rvt",pointcut="execution(* com.lfy.impl.*.*(..)) && args(arg0,arg1)")
public void log(Object rvt,String arg0,String arg1) {
...
}

上面的切入点表达式增加了&&args(arg0,arg1)部分,且log()方法还指定了它们是String类型,则该增强处理只匹配参数是两个个且均为String类型的目标方法。

如果表达式args部分为&&args(name,age, .. ),注意最后面是两点,这说明最少匹配两个参数(包括增强处理指定的类型),第三个参数可以是0到无限多个,且类型由增强处理决定,如:

@AfterReturning(returning="rvt",pointcut="execution(* com.lfy.impl.*.*(..)) && args(arg0,arg1,..)")
public void log(Object rvt,String arg0,String arg1,Date date) {
...
}

spring-第十七篇之spring AOP基于注解的零配置方式的更多相关文章

  1. Spring AOP基于注解的“零配置”方式实现

    为了在Spring中启动@AspectJ支持,需要在类加载路径下新增两个AspectJ库:aspectjweaver.jar和aspectjrt.jar.除此之外,Spring AOP还需要依赖一个a ...

  2. 8 -- 深入使用Spring -- 4...5 AOP代理:基于注解的“零配置”方式

    8.4.5 基于注解的“零配置”方式 AspectJ允许使用注解定义切面.切入点和增强处理,而Spring框架则可识别并根据这些注解来生成AOP代理.Spring只是使用了和AspectJ 5 一样的 ...

  3. 【学习】Spring 的 AOP :基于Annotation 的“零配置”方式

    转自:http://www.cnblogs.com/jbelial/archive/2012/07/20/2539123.html AOP(Aspect Orient Programming ) , ...

  4. spring自带的定时任务功能,基于注解和xml配置

    1.spring的配置文件 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi=&quo ...

  5. Spring Boot(十七):使用Spring Boot上传文件

    Spring Boot(十七):使用Spring Boot上传文件 环境:Spring Boot最新版本1.5.9.jdk使用1.8.tomcat8.0 一.pom包配置 <parent> ...

  6. 10 Spring框架--基于注解的IOC配置

    1.工程环境搭建 2.基于注解的IOC配置 IOC注解的分类 (1)用于创建对象的 他们的作用就和在XML配置文件中编写一个<bean>标签实现的功能是一样的@Component: 作用: ...

  7. 缓存初解(三)---Spring3.0基于注解的缓存配置+Ehcache和OScache

    本文将构建一个普通工程来说明spring注解缓存的使用方式,关于如何在web应用中使用注解缓存,请参见: Spring基于注解的缓存配置--web应用实例 一.简介 在spring的modules包中 ...

  8. Struts2基于注解的Action配置

    使用注解来配置Action的最大好处就是可以实现零配置,但是事务都是有利有弊的,使用方便,维护起来就没那么方便了. 要使用注解方式,我们必须添加一个额外包:struts2-convention-plu ...

  9. 缓存初解(五)---SpringMVC基于注解的缓存配置--web应用实例

    之前为大家介绍了如何使用spring注解来进行缓存配置 (EHCache 和 OSCache)的简单的例子,详见 Spring基于注解的缓存配置--EHCache AND OSCache 现在介绍一下 ...

随机推荐

  1. mybatis复习笔记(1):

    一.简介:什么是MyBatis 1.MyBatis是一款优秀的持久层框架,支持定制化SQL.存储过程以及高级映射.MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集.MyBatis ...

  2. canvas画随机的四位验证码

    效果图如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...

  3. 【知识强化】第二章 数据的表示和运算 2.4 算术逻辑单元ALU

    从本节开始我们就进入到本章的最后一节内容了,也就是我们算术逻辑单元的它的实现.这部分呢是数字电路的一些知识,所以呢,如果你没有学过数字电路的话,也不要慌张,我会从基础开始给大家补起.那么在计算机当中, ...

  4. Taro -- 微信小程序密码弹窗

    记录一个类似支付密码的弹窗写法,实现是否免密功能.如图: index.js   import Taro, { Component } from '@tarojs/taro'   import { Vi ...

  5. 【改】utf-8 的去掉BOM的方法

    最近在测试中发现,linux系统中导出的文件,有记事本打开另存为或者保存后,再次导入进linux系统,发现失败了,对比文件内容,没发现区别,打开二进制文件对比发现,文件头部多了三个字符:EF BB B ...

  6. 继承和构造函数语法造成的一个bug

    一 出错误的代码 开发环境: visual studio 2017 社区版 #include "pch.h" #include <iostream> #include ...

  7. java 创建匿名对象及声明map list时初始化

    java 创建匿名对象 类似于c# 中的 new { a:"aaa",b:"bbb"}; 1 创建匿名对象Object myobj = new Object() ...

  8. Task9.Attention

    注意力模型最近几年在深度学习各个领域被广泛使用,无论是图像处理.语音识别还是自然语言处理的各种不同类型的任务中,都很容易遇到注意力模型的身影.所以,了解注意力机制的工作原理对于关注深度学习技术发展的技 ...

  9. 吐血整理 | 1000行MySQL学习笔记,不怕你不会,就怕你不学!

    / Windows服务 / / 连接与断开服务器 / / 数据库操作 / ------------------ / 表的操作 / ------------------ / 数据操作 / ------- ...

  10. NVMe固态硬盘工具箱使用说明

    https://www.bilibili.com/read/cv562989/ 浦科特NVMe固态硬盘工具箱使用说明 数码 2018-6-7 687阅读7点赞3评论 浦科特已经推出针对NVMe固态硬盘 ...