天天看点

Spring(十)spring编写代理(aop编程)

Spring(八)jdk动态代理(AOP简单实现)

Spring(九)CGLIB字节码增强

这两篇文章写了两种方式的手动生成代理。我们应该如何使用spring自动生成代理呢

spring编写代理(半自动)

我们首先使用spring来模拟我们自己生成的代理步骤即半自动

目标类

public interface UserService {
    public void addUser();
    public void updateUser();
    public void deleteUser();
}      

切面类

切面类中确定通知,需要实现不同接口,接口就是规范,从而就确定方法名称。

采用“环绕通知” MethodInterceptor

public class MyAspect implements MethodInterceptor{

    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        System.out.println("前方法");
        Object obj=null;
        //执行目标类
        obj=mi.proceed();
        System.out.println("后方法");
        return      

spring配置

在创建代理类时,使用工厂bean factorybean 底层调用getObject返回特殊bean

proxyFactoryBean用于创建代理工厂bean 生成特殊代理对象。

interfaces : 确定接口们

通过可以设置多个值

只有一个值时,可以使用value=””

target : 确定目标类

interceptorNames : 通知 切面类的名称,类型String[],如果设置一个值 value=””

在上两篇文章中我们分别使用了jdk动态代理和cglib动态代理

在spring中我们可以通过设置​​

​<property name="optimize" value="true"></property>​

​​ 强制使用cglib 而在不声明optimize时

spring底层将判断目标类是否有接口,如果没有接口 使用cglib字节码增强,否则使用jdk动态代理。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 创建目标类 -->
    <bean id="userServiceId" class="com.scx.autoproxy.test.UserServiceImpl"></bean> 
    <!-- 创建切面类 -->  
    <bean id="myAspectId" class="com.scx.autoproxy.test.MyAspect"></bean>  
    <!-- 创建代理类--> 
    <bean id="proxyServiceId" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="interfaces" value="com.scx.autoproxy.test.UserService"></property>
        <property name="target" ref="userServiceId"></property>
        <property name="interceptorNames" value="myAspectId"></property>
    </bean>
</beans>      

测试

public void testProxy(){
        String xmlPath="com/scx/autoproxy/test/applicationContext.xml";
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath);
        UserService userService=(UserService) applicationContext.getBean("proxyServiceId");
        userService.addUser();
        userService.updateUser();
        userService.deleteUser();
    }      

运行结果:

Spring(十)spring编写代理(aop编程)

spring编写代理(全自动)

全自动和半自动相比较在于xml配置文件的代理类的编写

在半自动中,我们是通过模拟jdk动态代理的方式生成代理。在全自动中

使用aop命名空间实现。

spring配置

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/aop 
                            http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 创建目标类 -->
    <bean id="userServiceId" class="com.scx.autoproxy.test.copy.UserServiceImpl"></bean> 
    <!-- 创建切面类(通知) -->  
    <bean id="myAspectId" class="com.scx.autoproxy.test.copy.MyAspect"></bean>  
    <!-- 创建代理类--> 
    <aop:config proxy-target-class="true">
        <aop:pointcut expression="execution(* com.scx.autoproxy.test.copy.*.*(..))" id="myPointCut"/>
        <aop:advisor advice-ref="myAspectId" pointcut-ref="myPointCut"/>
    </aop:config>
</beans>      
execution(* com.scx.autoproxy.test.copy.*.*(..))
/*
    解释如下:
    execution选择方法
    *   返回值任意 
    com.scx.autoproxy.test.copy 包名   
    *   类名任意
    *   方法名任意
    ..  参数任意
*/      

测试

public void testProxy(){
        String xmlPath="com/scx/autoproxy/test/copy/applicationContext.xml";
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath);
        UserService userService=(UserService) applicationContext.getBean("userServiceId");
        userService.addUser();
        userService.updateUser();
        userService.deleteUser();
    }      

运行结果: