动态代理
代理模式:为其他对象提供一种代理以控制对这个对象的访问,增强一个类中的某个方法,对程序进行扩展。
动态代理可以在不修改类源码的前提下,给类中方法增加额外逻辑
通过cglib来实现的代理对象的创建:
基于父子类,被代理类是父类,代理类是子类,代理对象就是代理类的实例对象,代理类是由cglib创建的
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;// cglib动态代理单独使用
public class Test
{public static void main(String[] args){UserService target = new UserService();// 通过cglib技术Enhancer enhancer = new Enhancer();enhancer.setSuperclass(UserService.class);// 定义额外逻辑,也就是代理逻辑enhancer.setCallbacks(new Callback[] {new MethodInterceptor(){@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)throws Throwable{System.out.println("before...");
// // 写法一
// Object result = methodProxy.invoke(target, objects);// // 写法二
// Object result = method.invoke(target, objects);// 写法三Object result = methodProxy.invokeSuper(o, objects);System.out.println("after...");return result;}}});// 动态代理所创建出来的UserService对象UserService userService = (UserService)enhancer.create();// 执行这个userService的test方法时,就会额外会执行一些其他逻辑userService.test();}
}public class UserService
{public void test(){System.out.println("test");}
}
利用JDK动态代理来生成一个代理对象:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class Test
{public static void main(String[] args){UserService target = new UserService();// UserInterface接口的代理对象Object proxy = Proxy.newProxyInstance(UserService.class.getClassLoader(),new Class[] {UserInterface.class}, new InvocationHandler(){@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable{System.out.println("before...");Object result = method.invoke(target, args);System.out.println("after...");return result;}});// 注意这里必须是接口类型UserInterface,如果是UserService类会报错UserInterface userService = (UserInterface)proxy;userService.test();}
}public class UserService implements UserInterface
{@Overridepublic void test(){System.out.println("test");}
}public interface UserInterface
{public void test();
}
注意:代理对象proxy必须是接口类型
ProxyFactory
Spring对上面的两种动态代理技术进行了封装,封装出来的类叫做ProxyFactory
表示创建代理对象的一个工厂,使用起来更加方便
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactory;public class Test
{public static void main(String[] args){UserService target = new UserService();ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.setTarget(target);proxyFactory.addAdvice(new MethodInterceptor(){@Overridepublic Object invoke(MethodInvocation invocation)throws Throwable{System.out.println("before...");Object result = invocation.proceed();System.out.println("after...");return result;}});UserInterface userService = (UserInterface)proxyFactory.getProxy();userService.test();}
}public class UserService implements UserInterface
{@Overridepublic void test(){System.out.println("test");}
}public interface UserInterface
{public void test();
}
ProxyFactory会自动判断是用cglib还是jdk动态代理
如果类实现了接口,那么ProxyFactory底层就会用jdk动态代理
如果没有实现接口,就会用cglib技术
Advice的分类
1、Before Advice:方法之前执行
2、After returning advice:方法return后执行
3、After throwing advice:方法抛异常后执行
4、After (finally) advice:方法执行完finally之后执行,这是最后的,比return更后
5、Around advice:这是功能最强大的Advice,可以自定义执行顺序
Advisor
一个Advisor是有一个Pointcut和一个Advice组成的,通过Pointcut可以指定需要被代理的逻辑
可以通过Advisor来控制具体代理哪个方法
public class Test
{public static void main(String[] args){UserService target = new UserService();ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.setTarget(target);proxyFactory.addAdvisor(new PointcutAdvisor(){@Overridepublic Pointcut getPointcut(){return new StaticMethodMatcherPointcut(){@Overridepublic boolean matches(Method method, Class<?> targetClass){return method.getName().equals("testAbc");}};}@Overridepublic Advice getAdvice(){return new MethodInterceptor(){@Overridepublic Object invoke(MethodInvocation invocation)throws Throwable{System.out.println("before...");Object result = invocation.proceed();System.out.println("after...");return result;}};}@Overridepublic boolean isPerInstance(){return false;}});UserInterface userService = (UserInterface)proxyFactory.getProxy();userService.test();}
}
创建代理对象的方式
ProxyFactoryBean
public class UserService
{public void test(){System.out.println("test");}
}@ComponentScan(value = "com.gax")
public class AppConfig
{@Beanpublic ProxyFactoryBean userService(){UserService userService = new UserService();ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();proxyFactoryBean.setTarget(userService);proxyFactoryBean.addAdvice(new MethodInterceptor(){@Overridepublic Object invoke(MethodInvocation invocation)throws Throwable{System.out.println("before...");Object result = invocation.proceed();System.out.println("after...");return result;}});return proxyFactoryBean;}
}public class Test
{public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);UserService userServiceProxy = (UserService)applicationContext.getBean("userService");userServiceProxy.test();}
}
上面这种方式只能针对某一个Bean
ProxyFactoryBean还有额外的功能,比如可以把某个Advise或Advisor定义成为Bean,然后在ProxyFactoryBean中进行设置
public class UserService
{public void test(){System.out.println("test");}
}@ComponentScan(value = "com.gax")
public class AppConfig
{@Beanpublic MethodInterceptor gaxAroundAdvise(){return new MethodInterceptor(){@Overridepublic Object invoke(MethodInvocation invocation)throws Throwable{System.out.println("before...");Object result = invocation.proceed();System.out.println("after...");return result;}};}@Beanpublic ProxyFactoryBean userService(){UserService userService = new UserService();ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();proxyFactoryBean.setTarget(userService);proxyFactoryBean.setInterceptorNames("gaxAroundAdvise");return proxyFactoryBean;}
}public class Test
{public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);UserService userServiceProxy = (UserService)applicationContext.getBean("userService");userServiceProxy.test();}
}
BeanNameAutoProxyCreator
ProxyFactoryBean需要自己指定被代理的对象;BeanNameAutoProxyCreator可以通过指定某个bean的名字,来对该bean进行代理
通过BeanNameAutoProxyCreator可以对批量的Bean进行AOP,并且指定了代理逻辑,指定了一个InterceptorName,也就是一个Advise,前提条件是这个Advise也得是一个Bean,这样Spring才能找到的,但是BeanNameAutoProxyCreator的缺点很明显,它只能根据beanName来指定想要代理的Bean。
@Component
public class UserService
{public void test(){System.out.println("test");}
}@ComponentScan(value = "com.gax")
public class AppConfig
{@Beanpublic MethodInterceptor gaxAroundAdvise(){return new MethodInterceptor(){@Overridepublic Object invoke(MethodInvocation invocation)throws Throwable{System.out.println("before...");Object result = invocation.proceed();System.out.println("after...");return result;}};}@Beanpublic BeanNameAutoProxyCreator beanNameAutoProxyCreator(){BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();beanNameAutoProxyCreator.setBeanNames("userSe*");beanNameAutoProxyCreator.setInterceptorNames("gaxAroundAdvise");beanNameAutoProxyCreator.setProxyTargetClass(true);return beanNameAutoProxyCreator;}
}public class Test
{public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);UserService userServiceProxy = (UserService)applicationContext.getBean("userService");userServiceProxy.test();}
}
DefaultAdvisorAutoProxyCreator
@Component
public class UserService
{public void test(){System.out.println("test");}
}@ComponentScan(value = "com.gax")
public class AppConfig
{@Beanpublic MethodInterceptor gaxAroundAdvise(){return new MethodInterceptor(){@Overridepublic Object invoke(MethodInvocation invocation)throws Throwable{System.out.println("before...");Object result = invocation.proceed();System.out.println("after...");return result;}};}@Beanpublic DefaultPointcutAdvisor defaultPointcutAdvisor(){NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();pointcut.addMethodName("test");DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();defaultPointcutAdvisor.setPointcut(pointcut);defaultPointcutAdvisor.setAdvice(gaxAroundAdvise());return defaultPointcutAdvisor;}@Beanpublic DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();return defaultAdvisorAutoProxyCreator;}
}public class Test
{public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);UserService userServiceProxy = (UserService)applicationContext.getBean("userService");userServiceProxy.test();}
}
通过DefaultAdvisorAutoProxyCreator会直接去找所有Advisor类型的Bean,根据Advisor中的PointCut和Advice信息,确定要代理的Bean以及代理逻辑。
简化成注解方式:
@Aspect
@Component
public class GaxAspect
{@Before("execution(public void com.gax.service.UserService.test())")public void gaxBefore(JoinPoint joinPoint) {System.out.println("gaxBefore");}
}
要代理的类:表达式
代理逻辑:被@Before修饰的方法
Spring只要去解析这些注解就好了,解析之后得到对应的Pointcut对象、Advice对象,生成Advisor对象,扔进ProxyFactory中,进而产生对应的代理对象,具体怎么解析这些注解就是@EnableAspectJAutoProxy注解所要做的事情