什么是动态代理?
举个例子,生活中一般在打官司的时候都会请代理律师,为什么要请律师呢?是因为开庭的时候大部人对于打官司没有经验,只会说出自己案件的陈述,并不会根据法律等争取自己权益的最大化,此时就可以请律师帮助自己不仅完成对案件的陈述,还能争取权益最大化。那么Java中也是一样,如果要对功能进行增强就可以使用动态代理
它通过java反射机制,获取某个被代理类的所有接口,并创建代理类
为什么要用动态代理?
动态代理使我们免于去重写接口中的方法,而着重于去扩展相应的功能或是方法的增强,与静态代理相比简单了不少,减少了项目中的业务量
Java的JDK中Proxy类可以实现基于接口的动态代理,实现步骤示例如下:
1.核心类的接口
package com.wang.service;
public interface Actor {
void sring();
void dance();
void rap();
}
2. 实现核心接口中的抽象方法
package com.wang.service.impl;
import com.wang.service.Actor;
public class CXK implements Actor {
@Override
public void sring() {
System.out.println("顶你太美");
}
@Override
public void dance() {
System.out.println("丁丁舞");
}
@Override
public void rap() {
System.out.println("练习时长两年半");
}
}
3. 实现增强类
package com.wang.advice;
import com.wang.service.Actor;
import com.wang.service.impl.CXK;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JJGS {
public static void main(String[] args) {
//1.创建被代理类的对象----具体的人物cxk
Actor cxk = new CXK();
//2.创建代理的对象----具体某个人为上面cxk服务
/**
* Object proxy:被代理对象的引用,系统会自动创建被代理对象的一个映射
* Method method:被代理对象的方法
* Object[] args:被代理对象方法的参数
* 返回值是 被代理对象执行后的返回值
*/
Actor jjr = (Actor) Proxy.newProxyInstance(CXK.class.getClassLoader(), CXK.class.getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("演出前的增强: 联系业务");
System.out.println("演出前的增强:互联网造势");
System.out.println("演出前的增强:演出前的宣传");
//被代理对象方法的执行,并获得返回值
Object result=null;
result=method.invoke(cxk,args);
System.out.println("演出后的增强: 结算费用并纳税");
return result;
}
});
//3.有代理对象执行方法的时候不再是被代理对象执行方法,而是由我们的代理类对象执行方法
jjr.rap();
}
}
基于子类的CGLib动态代理,可以使用Enhancer类完成直接对某个类进行动态代理。具体操作步骤如下:
导入lib中的jar包
1.核心类的接口
package com.wang.service;
public interface BookService {
//添加
int save(int n);
//删除
int del();
//修改
int update();
//查询
void find();
}
2.实现核心类的抽象方法
package com.wang.service.impl;
import com.wang.service.BookService;
public class BookServiceImpl implements BookService {
@Override
public int save(int n) {
System.out.println("添加");
return 1;
}
@Override
public int del() {
System.out.println("删除");
return 1;
}
@Override
public int update() {
System.out.println("修改");
return 1;
}
@Override
public void find() {
System.out.println("查询");
}
}
3.编写代理类
package com.wang.advice;
public class Loger {
public void before(){
System.out.println("前置通知: 执行日志的打印");
}
public void after(){
System.out.println("后置通知:执行日志的打印");
}
public void afterThrowingPrintLog(){
System.out.println("异常通知");
}
public void afterPrintLog(){
System.out.println("最终通知:作资源的释放");
}
}
4编写动态代理的xml文件
<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: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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 1.把所有类的对象交给IOC容器进行管理 -->
<bean id="loger" class="com.wang.advice.Loger"/>
<bean id="bookService" class="com.wang.service.impl.BookServiceImpl"/>
<!-- 2.AOP的配置:让增强类 的 哪个方法 动态进行何种增强 核心类 的 哪个方法 -->
<aop:config>
<aop:aspect id="log" ref="loger">
<aop:before method="before" pointcut="execution(* *..BookServiceImpl.*(..))"/>
<aop:after-returning method="afterPrintLog" pointcut="execution(* *..BookServiceImpl.*(..))"/>
<aop:after-throwing method="afterThrowingPrintLog" pointcut="execution(* *..BookServiceImpl.*(..))"/>
<aop:after method="after" pointcut="execution(* *..BookServiceImpl.*(..))"/>
</aop:aspect>
</aop:config>
</beans>
5.测试类(执行核心文件中的添加方法,完成增强功能)
package com.wang.servlet;
import com.wang.service.BookService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test01 {
@Test
public void test01(){
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
BookService bookService = context.getBean(BookService.class);
bookService.save(1);
}
}
结果为: