Spring学习笔记(16)--------------Spring AOP总结(1)
来源:互联网 发布:安卓编程类游戏 编辑:程序博客网 时间:2024/05/21 22:39
- 前置增强
- 后置增强
- 环绕增强
- 异常抛出增强
- 引介增强
public interface Waiter { void greetTo(String name); void serveTo(String name);}
public class NaiveWaiter implements Waiter { @Override public void greetTo(String name) { System.out.println("greet to "+name+"..."); } @Override public void serveTo(String name) { System.out.println("serving "+name+"..."); }}
public class GreetingBeforAdvice implements MethodBeforeAdvice { /** * method 为目标类的方法 * * args 为目标类的入参 * * obj 为目标类的实例 */ @Override public void before(Method method, Object[] args, Object target) throws Throwable { String clientName = (String) args[0]; System.out.println("How are you! Mr " + clientName + "."); // System.out.println(target.getClass().getName()); }}
5.advisor 上场
public class TestBeforAdvice { public static void main(String[] args) { Waiter target=new NaiveWaiter(); BeforeAdvice beforeAdvice=new GreetingBeforAdvice(); //spring 提供的代理工厂 ProxyFactory pf=new ProxyFactory(); //设置代理目标 pf.setTarget(target); //为代理目标添加增强 pf.addAdvice(beforeAdvice); //生成代理实例 Waiter waiter=(Waiter) pf.getProxy(); waiter.greetTo("John"); waiter.serveTo("Tom"); }}
public interface UserManagement { void addUser(String name,int age); String deleteUser(String...str); }
import com.yc.jdk.proxy.UserManagement; public class UserManagementImpl implements UserManagement { public void addUser(String name, int age) { System.out.println("add"); } public String deleteUser(String... str) { System.out.println("delete"); return "delete"; }}3.继承jdk中的代理类InvocationHandlerimport java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class CheckSecurity implements InvocationHandler {//声明目标类private Object targetObject;/*** 传入要代理的对象* * @param targetObject* @return object*/public Object CheckSecurity(Object targetObject) {this.targetObject = targetObject;return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(), this.targetObject.getClass().getInterfaces(), this);}//模拟 环绕代理方法public Object invoke(Object proxy, Method method, Object[] args)throws Throwable { checkseiurity(); Object chckObject = null; // 获取方法名称 p("method name value ", method.getName()); // 取得此方法是不是可变参数 p("method is var args ", method.isVarArgs()); System.out.println(args.length); try { chckObject = method.invoke(this.targetObject, args); } catch (RuntimeException e) { e.printStackTrace(); } checkseiurity(); return chckObject;}
private void checkseiurity() { System.out.println("--------------check----------------"); }
public void p(Object... object) { for (int i = 0; i < object.length; i++) { System.out.print(object[i].toString()); }// 产生换行 System.out.println(); }}4.测试jdk动态代理import java.lang.reflect.Proxy;import com.yc.jdk.proxy.impl.UserManagementImpl;public class JdkPorxy { public static void main(String[] args) throws Exception { CheckSecurity checkSecurity = new CheckSecurity(); UserManagement management = (UserManagement) checkSecurity.CheckSecurity(new UserManagementImpl()); p(Proxy.isProxyClass(UserManagement.class)); // management.addUser("张三", 12); management.deleteUser("张三", "李四", "王五", "赵六"); } public static void p(Object object) { System.out.println(object.toString()); }}
运行结果:
Spring 定义了org.springframework.aop.framework.AopProxy接口,并提供了两个final类型实现类
import org.springframework.aop.BeforeAdvice;import org.springframework.aop.framework.ProxyFactory;import com.web.spring.aop.example.beforadvice.GreetingBeforAdvice;import com.web.spring.aop.example.beforadvice.NaiveWaiter;import com.web.spring.aop.example.beforadvice.Waiter;/** * @author Chris * */public class TestProxyFactory { public static void main(String[] args) { //cglibProxyMethod(); jdkProxyMethod(); } public static void jdkProxyMethod() { Waiter target = new NaiveWaiter(); BeforeAdvice beforeAdvice = new GreetingBeforAdvice(); ProxyFactory proxyFactory = new ProxyFactory(); // 指向jdk代理 proxyFactory.setInterfaces(target.getClass().getInterfaces()); proxyFactory.setTarget(target); proxyFactory.addAdvice(beforeAdvice); create(proxyFactory); } public static void cglibProxyMethod() { Waiter target = new NaiveWaiter(); BeforeAdvice beforeAdvice = new GreetingBeforAdvice(); ProxyFactory proxyFactory = new ProxyFactory(); //强制使用cglib代理 proxyFactory.setOptimize(true); proxyFactory.setTarget(target); proxyFactory.addAdvice(beforeAdvice); create(proxyFactory); } private static void create(ProxyFactory proxyFactory) { Waiter waiter = (Waiter) proxyFactory.getProxy(); waiter.greetTo("John"); waiter.serveTo("Tom"); }}
<?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:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" 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/util http://www.springframework.org/schema/util/spring-util-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"> <bean id="greetingAdvice" class="com.web.spring.aop.example.beforadvice.GreetingBeforAdvice"/> <bean id="target" class="com.web.spring.aop.example.beforadvice.NaiveWaiter"/> <!--ProxyFactoryBean 是FactoryBean接口的实现类 --> <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean" p:proxyInterfaces="com.web.spring.aop.example.beforadvice.Waiter" p:interceptorNames="greetingAdvice" p:target-ref="target" p:proxyTargetClass="true" /><!-- 1.proxyInterfaces代理所要实现的接口,可以是多个接口。该属性还有一个别名interfaces 2.interceptorNames需要织入目标对象的bean列表,采用Bean的名称指定。这些Bean必须实现了 org.aopalliance.intercept.MethodInterceptor或 org.springframework.aop.Advisor 的Bean,配置中的顺序对应调用的顺序。 3.singleton 返回的代理是否是简单实例,默认为单实例; 4.optimize 当设置成true 时,强制使用Cglib代理。 5.proxyTargetClass 是否对类进行代理(而不是对接口进行代理),设置为true时,使用CGLib代理。 --></beans>
和CGLIB不同的是,JDK代理只能代理接口,不能代理类。
使用JDK代理时,如何处理一个特定的方法调用的决定是在程序运行时做出的,也就是在每次方法被调用时。使用CGLIB代理可以边开这种处理方法,CGLIB会在运行中随时为代理创建新类的字节码,并尽可能的重用已经生成的类的字节码。
Spring AOP部分使用JDK动态代理或者CGLIB来为目标对象创建代理。(建议尽量使用JDK的动态代理)
如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理。所有该目标类型实现的接口都将被代理。若该目标对象没有实现任何接口,则创建一个CGLIB代理。
如果你希望强制使用CGLIB代理,(例如:希望代理目标对象的所有方法,而不只是实现自接口的方法)那也可以。但是需要考虑以下问题:
无法通知(advise)Final 方法,因为他们不能被覆写。
你需要将CGLIB 2二进制发行包放在classpath下面,与之相较JDK本身就提供了动态代理
强制使用CGLIB代理需要将 |aop:config| 的 proxy-target-class 属性设为true:
|aop:config proxy-target-class="true"|
...
|/aop:config|
当需要使用CGLIB代理和@AspectJ自动代理支持,请按照如下的方式设置 |aop:aspectj-autoproxy| 的 proxy-target-class 属性:
|aop:aspectj-autoproxy proxy-target-class="true"/|
而实际使用的过程中才会发现细节问题的差别,The devil is in the detail.JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理。
CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB是高效的代码生成包,底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的,性能比JDK强。
Spring是依靠什么来判断采用哪种代理策略来生成AOP代理呢?以下代码就是Spring的判断逻辑
//org.springframework.aop.framework.DefaultAopProxyFactory //参数AdvisedSupport 是Spring AOP配置相关类 public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException { //在此判断使用JDK动态代理还是CGLIB代理 if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(advisedSupport)) { if (!cglibAvailable) { thrownew AopConfigException( "Cannot proxy target class because CGLIB2 is not available. " +"Add CGLIB to the class path or specify proxy interfaces."); } return CglibProxyFactory.createCglibProxy(advisedSupport); } else { returnnew JdkDynamicAopProxy(advisedSupport); } }
advisedSupport.isOptimize()与advisedSupport.isProxyTargetClass()默认返回都是false,所以在默认情况下目标对象有没有实现接口决定着Spring采取的策略,当然可以设置advisedSupport.isOptimize()或者advisedSupport.isProxyTargetClass()返回为true,这样无论目标对象有没有实现接口Spring都会选择使用CGLIB代理。
所以在默认情况下,如果一个目标对象如果实现了接口Spring则会选择JDK动态代理策略动态的创建一个接口实现类(动态代理类)来代理目标对象,可以通俗的理解这个动态代理类是目标对象的另外一个版本,所以这两者之间在强制转换的时候会抛出java.lang.ClassCastException。而所以在默认情况下,如果目标对象没有实现任何接口,Spring会选择CGLIB代理, 其生成的动态代理对象是目标类的子类。
上说的是默认情况下,也可以手动配置一些选项使Spring采用CGLIB代理。
org.springframework.transaction.interceptor.TransactionProxyFactoryBean是org.springframework.aop.framework. ProxyConfig的子类,所以可以参照ProxyConfig里的一些设置如下所示,将optimize和proxyTargetClass任意一个设置为true都可以强制Spring采用CGLIB代理。
如果当需要使用CGLIB代理和@AspectJ自动代理支持,请按照如下的方式设置 |aop:aspectj-autoproxy| 的 proxy-target-class 属性:
|aop:aspectj-autoproxy proxy-target-class="true"/|
这样使用CGLIB代理也就不会出现前面提到的ClassCastException问题了,也可以在性能上有所提高,关键是对于代理对象是否继承接口可以统一使用。
两种类型AOP:静态AOP和动态AOP。
静态代理:
代理对象与被代理对象必须实现同一个接口。
demo:
- package cn.partner4java.proxy.staticproxy;
- /**
- * 静态代理,统一接口
- * @author partner4java
- *
- */
- public interface IHello {
- /**
- * 可以带来的统一方法
- * @param name
- */
- public void hello(String name);
- }
- package cn.partner4java.proxy.staticproxy;
- /**
- * 被代理的对象,需要借助代理对象加入日志
- * @author partner4java
- *
- */
- public class HelloSpeaker implements IHello {
- public void hello(String name) {
- System.out.println("Hello " + name);
- }
- }
- package cn.partner4java.proxy.staticproxy;
- /**
- * 代理对象,给被代理对象添加日志
- */
- public class HelloProxy implements IHello {
- private IHello iHello;
- public HelloProxy(IHello iHello) {
- super();
- this.iHello = iHello;
- }
- public void hello(String name) {
- System.out.println("记录日志");
- iHello.hello(name);
- }
- }
- package cn.partner4java.proxy.staticproxy;
- /**
- * 调用
- * @author partner4java
- *
- */
- public class ProxyDemo {
- public static void main(String[] args) {
- IHello iHello = new HelloProxy(new HelloSpeaker());
- iHello.hello("long");
- }
- }
动态代理:
动态代理区别于静态带来实现的地方在于织入过程是在运行时动态进行的。自己实现一般实现java.lang.reflect.InvocationHandler接口。
例子:
- package cn.partner4java.proxy.dynamicproxy;
- public interface IHello {
- public void hello(String name);
- }
- package cn.partner4java.proxy.dynamicproxy;
- /**
- * 被代理的对象,需要借助代理对象加入日志
- * @author partner4java
- *
- */
- public class HelloSpeaker implements IHello {
- public void hello(String name) {
- System.out.println("Hello " + name);
- }
- }
- package cn.partner4java.proxy.dynamicproxy;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- /**
- * 动态代理对象
- * @author partner4java
- *
- */
- public class LogHandler implements InvocationHandler {
- private Object delegate;
- public Object bind(Object delegate){
- this.delegate = delegate;
- return Proxy.newProxyInstance(delegate.getClass().getClassLoader(),
- delegate.getClass().getInterfaces(), this);
- }
- /**
- * 代理对象,这里面还可以改变原有的方法
- */
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- Object result = null;
- try {
- System.out.println("添加日志");
- result = method.invoke(delegate, args);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
- }
- package cn.partner4java.proxy.dynamicproxy;
- /**
- * 测试
- * @author partner4java
- *
- */
- public class ProxyDemo {
- public static void main(String[] args) {
- LogHandler logHandler = new LogHandler();
- IHello iHello = (IHello) logHandler.bind(new HelloSpeaker());
- iHello.hello("long");
- }
- }
------------------------------------------------------------------
利用ProxyFactory连接CGLIB简单实现AOP:
加入包aopalliance.jar\cglib-nodep-2.1_3.jar
demo:
- package cn.partner4java.proxy.proxyfactory;
- /**
- * 被代理的对象
- * @author partner4java
- *
- */
- public class MessageWriter {
- public void writeMessage(){
- System.out.println("world!");
- }
- }
- package cn.partner4java.proxy.proxyfactory;
- import org.aopalliance.intercept.MethodInterceptor;
- import org.aopalliance.intercept.MethodInvocation;
- /**
- * 装饰者<br/>
- * MethodInterceptor接口是对方法调用连接点实现包围通知的AOP联盟标准接口
- * @author partner4java
- *
- */
- public class MessageDecorator implements MethodInterceptor{
- public Object invoke(MethodInvocation invocation) throws Throwable {
- System.out.print("Hello ");
- Object retVal = invocation.proceed();
- return retVal;
- }
- }
- package cn.partner4java.proxy.proxyfactory;
- import org.springframework.aop.framework.ProxyFactory;
- /**
- * 调用组装
- * 这里最重要的部分是我们使用ProxyFactory来创建一个目标对象代理,同时织入通知
- * @author partner4java
- *
- */
- public class HelloWorldWeaver {
- public static void main(String[] args) {
- //目标
- MessageWriter target = new MessageWriter();
- //create the proxy
- ProxyFactory proxyFactory = new ProxyFactory();
- proxyFactory.addAdvice(new MessageDecorator());
- proxyFactory.setTarget(target);
- //获取返回被代理的目标
- MessageWriter proxy = (MessageWriter) proxyFactory.getProxy();
- target.writeMessage();
- System.out.println("---");
- proxy.writeMessage();
- // 后台打印:
- // world!
- // ---
- // World world!
- }
- }
- Spring学习笔记(16)--------------Spring AOP总结(1)
- [Spring]Spring AOP学习笔记(3)---Spring JDBC总结
- [Spring]Spring AOP学习笔记(1)
- Spring学习笔记(17)-----------Spring AOP总结(2)
- Spring AOP学习笔记(1):AOP基础知识
- [Spring]Spring AOP学习笔记(4)--Spring 事务
- Spring学习总结(9)——Spring AOP总结
- Spring框架AOP学习总结(一)
- Spring学习-----AOP(1)
- Spring 学习笔记 (二)--AOP
- Spring学习笔记(二)AOP入门
- Spring学习笔记(12)----------aop
- Spring学习笔记(四)-----AOP
- Spring学习总结(4)——Spring AOP教程
- spring AOP学习总结
- Spring AOP 学习总结
- Spring学习笔记(二)----Spring AOP配置与应用
- Spring学习笔记(三)Spring注解方式实现AOP
- 基于MVC3 Razor视图引擎的富文本运用
- fun:数字字符转换成大写人民币通用方法封装
- VMware虚拟机安装ubuntu的时候卡在vmwaretools
- github的使用步骤
- Foundation_编码相互转化,数据转化
- Spring学习笔记(16)--------------Spring AOP总结(1)
- Android 动画效果——Animation 动画
- Xcode快速Doxygen文档注释 — 简明图文教程(3分钟后爽歪歪)
- iOS 使用系统默认声音、震动
- eClipase中如何查看JSP编译后的Java文件
- fzu2190
- cin>>,cin.get(),cin.getline()的一些用法
- C#中 winform只允许运行单个实例,并且会用Application.Restart();
- 转:如何关闭cocos2d调试时输出的log(http://blog.sina.com.cn/s/blog_46f079f80101h8il.html)