Spring-动态代理

动态代理

代理模式:为其他对象提供一种代理以控制对这个对象的访问,增强一个类中的某个方法,对程序进行扩展。

动态代理可以在不修改类源码的前提下,给类中方法增加额外逻辑

通过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()
        {
            @Override
            public 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()
            {
                @Override
                public 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
{
    @Override
	public 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()
        {
            @Override
            public 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
{
    @Override
	public 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()
        {
            @Override
            public Pointcut getPointcut()
            {
                return new StaticMethodMatcherPointcut()
                {
                    @Override
                    public boolean matches(Method method, Class targetClass)
                    {
                        return method.getName().equals("testAbc");
                    }
                };
            }
            
            @Override
            public Advice getAdvice()
            {
                return new MethodInterceptor()
                {
                    @Override
                    public Object invoke(MethodInvocation invocation)
                        throws Throwable
                    {
                        System.out.println("before...");
                        Object result = invocation.proceed();
                        System.out.println("after...");
                        return result;
                    }
                };
            }
            
            @Override
            public 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
{
	@Bean
    public ProxyFactoryBean userService()
    {
        UserService userService = new UserService();
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setTarget(userService);
        proxyFactoryBean.addAdvice(new MethodInterceptor()
        {
            @Override
            public 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
{
	@Bean
    public MethodInterceptor gaxAroundAdvise()
    {
        return new MethodInterceptor()
        {
            @Override
            public Object invoke(MethodInvocation invocation)
                throws Throwable
            {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        };
    }
    
    @Bean
    public 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
{
	@Bean
    public MethodInterceptor gaxAroundAdvise()
    {
        return new MethodInterceptor()
        {
            @Override
            public Object invoke(MethodInvocation invocation)
                throws Throwable
            {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        };
    }
    
    @Bean
    public 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
{
	@Bean
    public MethodInterceptor gaxAroundAdvise()
    {
        return new MethodInterceptor()
        {
            @Override
            public Object invoke(MethodInvocation invocation)
                throws Throwable
            {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        };
    }
    
    @Bean
    public DefaultPointcutAdvisor defaultPointcutAdvisor()
    {
        NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
        pointcut.addMethodName("test");
        
        DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
        defaultPointcutAdvisor.setPointcut(pointcut);
        defaultPointcutAdvisor.setAdvice(gaxAroundAdvise());
        
        return defaultPointcutAdvisor;
    }
    
    @Bean
    public 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注解所要做的事情

你可能感兴趣的:(spring,java)