Spring框架 AOP----动态代理技术

1.AOP优点

AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码

2.AOP底层原理(简介)

aop底层原理就是动态代理技术 。动态代理技术又分为jdk动态代理和cglib动态代理,什么叫代理?代理就相当于现实生活中的中介或经纪人。

一、 jdk动态代理

jdk动态代理技术必须目标类实现了某个接口,否则无法使用jdk动态代理技术, jdk动态代理底层是使用的字节拼码接技术(ASM框架),本质是动态生成了,一个UserDao接口的实现类 $Proxy0类

首先编写一个接口

public interface UserDao {
    
    
    int add(int a, int b);
}

然后再编写实现类实现接口

public class UserDaoImpl  implements UserDao{
    
    
    @Override
    public int add(int a, int b) {
    
    
        return a+b;
    }
}

这个时候编写一个测试类所得的结果是正确的,然后我们再来编写一个“黑客类” 实现InvocationHandler接口

public class JdkHk implements InvocationHandler{
    
    
    Object target;//目标
    public JdkHk(Object target) {
    
    
        this.target = target;
    }
    /**
     * 入侵目标的方法
     * proxy:代理对象
     * method: 目标对象的方法
     * args:调用目标对象方法传递过参数
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
        System.out.println("====亲,你被入侵了===");
        //改变传入的参数
        args[0]=100;
        args[1]=2;
        //调用目标方法
        System.out.println("======鉴权成功=====");
        Object result = method.invoke(target, args);
        System.out.println("result=="+result);
        System.out.println("======记录成功======");
        return result;
    }

}

最后我们再来测试

public class TestOne {
    
    
    public static void main(String[] args) {
    
    
        
        // 一、正常调用
        UserDao userDao = new UserDaoImpl();
        int result = userDao.add(3, 5);
        System.out.println(result);
        // 二、jdkHk入侵调用

        // 1.目标对象
        UserDao target = new UserDaoImpl();
        // 2.黑客对象
        JdkHk jdkHk = new JdkHk(target);
        // 3.生产代理对象
        UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
                new Class[] {
    
     UserDao.class }, jdkHk);
        result = userDaoProxy.add(3, 50);

    }
}

运行结果
在这里插入图片描述
总结:JDK动态代理只能代理实现接口的目标对象

扫描二维码关注公众号,回复: 12438498 查看本文章

二、cglib动态代理

创建一个用来入侵的“黑客”类

public class SpringProxy implements MethodInterceptor {
    
    
	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
    
    
		System.out.println("spring代理前");
		//执行方法
		Object obj = invocation.proceed();
		System.out.println("spring代理后");
		return obj;
	}
}

配置xml文件(这里文件的路径按照自己的写)

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 1、目标对象 -->
    <bean id="target2" class="com.cc.dao.impl.UserDaoImpl"></bean>
    <!-- 2、黑客对象 -->
    <bean id="jdkHk" class="com.cc.proxy.JdkHk">
        <constructor-arg value=""/>
    </bean>
     <!--3、代理对象:是目标对象与黑客对象融合体(jdk) -->
     <bean  id="userDaoProxyJdk" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="proxyInterfaces"  value="com.cc.dao.UserDao"></property>
        <!-- 1)注入目标对象 -->
        <property name="target"  ref="target2"/>
        <!-- 2)黑客对象  -->
        <property name="interceptorNames">
            <array>
                <value>jdkHk</value>
            </array>
        </property>
    </bean>
  </beans>

最后编写测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-beans.xml")
public class SpringHkTest {
    
    
    @Autowired//默认按类型注入,通过@Qualifier修改为按名称注入
    @Qualifier("userDaoProxy")
    private UserDaoImpl2 userDao2;//cglib
    @Autowired
    @Qualifier("userDaoProxy2")
    //@Resource(name="userDaoProxy2")//默认按类型注入,通过@Qualifier修改为按名称注入
    private UserDao userDao;//jdk
    @Test
    public void test01() {
    
    
        //目标没有实现接口--cglib
        System.out.println(userDao2.add(3, 5));
    }
}
总结:
Spring框架,如果类实现了接口,就使用JDK的动态代理生成代理对象,如果这个类没有实现任何接口,使用CGLIB生成代理对象
当然也可以通过 ProxyFactoryBean的ProxyTargetClass属性设置为true,强制使用cglib动态代理
Cglib动态代理是为目标类生成代理类(子类)、JDK动态代理是为目标接口生成代理类(子类),而非目标类的代理类。
Cglib既可以代理没有接口的目标对象,也可以代理实现接口的目标对象!!!

猜你喜欢

转载自blog.csdn.net/weixin_52841956/article/details/111327408