Spring原生的经典模式 实现 AOP
通知:
前置通知:在目标方法执行之前执行,不能改变方法的执行流程和结果!
实现 MethodBeforeAdvice接口!
后置通知:在目标方法执行之后执行,不能改变方法的执行流程和结果!
实现 AfterReturningAdvice接口!
环绕通知:方法的拦截器!可以改变方法的执行流程和结果!
实现 MethodInterceptor接口!
异常通知:当我们的目标方法出现异常时才执行的方法!
实现ThrowsAdvice接口! 实现各种增强(通知 advice)的步骤: 01.引入两个jar 一个是aop联盟 spring-aop
02.创建对应的接口和实现类(主业务)
03.创建对应的增强处理类(系统级业务)
04.在spring容器中配置 目标类对象和通知对象
05.配置ProxyFactoryBean(代理工厂类) 问题:
01.如果我们有多个serviceImpl! 这时候ProxyFactoryBean不能配置多个目标对象!
02.ProxyFactoryBean给目标对象中的所有主业务都做了增强!不能指定某个主业务!

<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">
<parent>
<artifactId>Spring</artifactId>
<groupId>com.xdf</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion> <artifactId>09SpringAop</artifactId>
<packaging>jar</packaging> <name>09SpringAop</name>
<url>http://maven.apache.org</url> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!--spring对应的版本号-->
<spring.version>4.2.1.RELEASE</spring.version>
</properties> <dependencies>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency> <!--引入需要的spring 核心jar-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency> <dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency> <!--引入mysql的驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.26</version>
</dependency> <!--配置jdbc需要的数据源-->
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.6</version>
</dependency> <dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency> <dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency> <!--SpringJDBC需要的jar-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency> </dependencies>
</project>
public interface UserService {

    //主业务
String eat();
//主业务
void sleep();
}
// 目标类    impl包下的UserServiceImpl
public class UserServiceImpl implements UserService{ //主业务
public String eat() {
System.out.println("正在吃小苹果......");
return "apple";
} //主业务
public void sleep() {
System.out.println("正在休息......");
}
}

  定义的通知(增强)

//异常通知
public class ExceptionAdvice implements ThrowsAdvice { /**
* @param ex 用户名异常
*/
public void afterThrowing(UserNameException ex){
System.out.println(ex.getMessage());
}
/**
* @param ex 年龄异常
*/
public void afterThrowing(AgeException ex){
System.out.println(ex.getMessage());
}
}
//前置通知
public class BeforeAdvice implements MethodBeforeAdvice {
/**
* 在目标方法执行之前
* @param method 目标方法
* @param args 目标方法的参数列表
* @param target 目标对象
* @throws Throwable
*/
public void before(Method method, Object[] args, Object target) throws Throwable {
/* System.out.println("target的名称====》"+target);
System.out.println("method的名称====》"+method.getName());*/
System.out.println("执行**** 前置**** 通知");
}
}
//环绕通知
public class AroundAdvice implements MethodInterceptor { /**
* 在前置通知 之后,后置通知之前执行环绕通知!
* 可以获取方法的返回值,并且改变!
* @param methodInvocation 方法的执行器, getMethod 包含了方法中的所有方法
* @return
*/
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("执行方法之前的 环绕通知");
//执行目标方法
Object result= methodInvocation.proceed();
if (result!=null){
result="xiaoheihei";
}
System.out.println("执行方法之后的 环绕通知");
return result;
}
}
//后置通知
public class AfterAdvice implements AfterReturningAdvice {
/**
* 在目标方法执行之后
* @param returnValue 目标方法的返回值 我们可以获取返回值 但是不能操作返回值
* @param method 目标方法
* @param args 目标方法的参数列表
* @param target 目标对象
* @throws Throwable
*/
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
/* System.out.println("target的名称====》"+target);
System.out.println("returnValue====》"+returnValue);
System.out.println("method的名称====》"+method.getName());*/
System.out.println("执行**** 后置**** 通知");
}
}

  

  定义的异常文件夹

//验证异常通知的接口
public interface ExceptionService { public boolean checkUser(String userName,int age) throws UserException;
}
public class UserServiceImpl implements ExceptionService {

    public boolean checkUser(String userName, int age) throws UserException {
if (!"admin".equalsIgnoreCase(userName)){
throw new UserNameException("用户名错误");
}
if (age<20){
throw new AgeException("年龄错误");
}
return true;
}
}
//用户的异常类
public class UserException extends Exception{ public UserException(String msg){
super(msg);
} }
//用户名异常类
public class UserNameException extends UserException { public UserNameException(String msg) {
super(msg);
}
}
//年龄异常类
public class AgeException extends UserException { public AgeException(String msg) {
super(msg);
}
}
<?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"
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"> <bean id="userService" class="cn.happy.service.impl.UserServiceImpl"/> <bean id="before" class="cn.happy.service.advices.BeforeAdvice"/> <bean id="after" class="cn.happy.service.advices.AfterAdvice"/> <bean id="around" class="cn.happy.service.advices.AroundAdvice"/> <bean id="userException" class="cn.happy.service.exceptionPackage.UserServiceImpl"/> <bean id="myException" class="cn.happy.service.advices.ExceptionAdvice"/> <!--03.通知配置代理工厂bean,生成代理类,来把通知织入到目标对象
问题:只能管理 通知!
01.只能将切面织入到目标类的所有方法中
02.只能配置一个目标对象
-->
<bean id="userProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="userService"/>
<!--前置,后置的通知: value第一种方法-->
<!--<property name="interceptorNames" value="before,after"/>-->
<!--前置,后置,环绕的通知 value第二种方法-->
<property name="interceptorNames">
<array><!--这里要定义array-->
<value>before</value>
<value>after</value>
<value>around</value>
</array>
</property>
</bean> <bean id="exceptionProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetName" value="userException"/>
<property name="interceptorNames">
<array>
<value>myException</value>
</array>
</property>
<!--代理类的优化 是否使用cglib动态代理-->
<property name="optimize" value="true"/>
</bean>
</beans>

<property name="proxyTargetClass" value="true"/>
proxyTargetClass:默认是false,默认执行jdk动态代理!
设置成true,强制执行cglib!
optimize:代理类的优化
有接口就是用jdk,没有接口使用cglib动态代理
我们的动态代理 (在程序运行期间,动态生成的代理类) 分为两种方式:
  01.jdk 只能应用于实现接口的情况
  02.cglib 应用于实现接口和类的情况
如果我们是接口的情况,使用jdk效率高!
如果我们是类的情况,必须使用cglib!
问题?
  程序 spring容器怎么知道我们是用的类还是接口??
  public class ProxyConfig implements Serializable
  private boolean proxyTargetClass = false;
  private boolean optimize = false;
  spring底层默认使用cglib! 现在我们的项目中使用的是接口!
  用spring默认的性能不高!
  proxyTargetClass 和optimize都是用来设置 我们使用的代理模式是jdk还是cglib!

    @Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 根据我们配置文件中 proxyTargetClass 和 optimize的配置
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
//根据目标对象返回对应的动态代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}

09SpringAopAdvice的更多相关文章

随机推荐

  1. bootstrap框架日期时间 开始日期和结束日期选择

    页面表单查询时,常要求要查询一个日期时间段内的数据,若采用bootstrap框架的datetimepicker插件来控制,需要了解怎么个用法:

  2. BZOJ_1999_[Noip2007]Core树网的核_单调队列+树形DP

    BZOJ_1999_[Noip2007]Core树网的核_单调队列+树形DP Description 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边带有正整数的权,我们称T ...

  3. bzoj 3267: KC采花&&3272&&3638&&3502 线段树

    题目大意 给定一个长为n的序列,维护两种操作: 1.单点修改 2.在[l,r]这段区间中取k个互不相交的子段,使子段之和最大. \(n \leq 50000,k \leq 20\) 题解 四倍经验.( ...

  4. codevs 2144 砝码称重2

    传送门 2144 砝码称重 2  时间限制: 1 s  空间限制: 16000 KB  题目等级 : 钻石 Diamond 题解   题目描述 Description 有n个砝码,现在要称一个质量为m ...

  5. NFS安装

    安装应用 yum install -y nfs-utils rpcbind   服务器端: 1.启动服务 service nfs start service rpcbind start   2. 编辑 ...

  6. poj2777Count Color——线段树+状压

    题目:http://poj.org/problem?id=2777 状压每个颜色的选择情况,取答案时 | 一番: 注意题目中的区间端点可能大小相反,在读入时换一下位置: 注意pushdown()中要l ...

  7. 【VS工程设置】 编译动态库,命令行添加参数,不使用预编译头,指定该项目链接 哪种 运行库

    编译动态库 注意: 动态库: [目标文件扩展] => .dll + [配置类型] => 动态库(.dll) 静态库: [目标文件扩展] => .lib + [ 配置类型]=> ...

  8. openStack vm备份

    由于VM是可能存在于不同节点上,所以当一个计算节点挂掉后,可以把挂掉的节点运行的VM在新的节点上继续运行. 虽然快照功能可以做恢复使用,但是毕竟快照只能恢复固定时间的VM,所以虚拟机备份很重要!对做好 ...

  9. 如何在VS2015中使用Git命令提示符

    本文转载自 http://qkxue.net/info/176223/Visual-Studio-Git VS2015自带了Git插件,但有时候觉得Git控制台命令更方便些.VS中本身不能把Git B ...

  10. Centos7 使用 supervisor 管理进程

    一.安装 //直接使用pip安装(pip的安装 http://www.cnblogs.com/yxhblogs/p/8971251.html) pip install supervisor 二.配置 ...