09SpringAopAdvice
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); } }