什么是动态代理?
使用jdk的反射机制,创建对象的能力,创建的是代理类的对象。而不用你创建类文件。不用谢java文件。
动态:在程序执行时,调用JDK提供的方法才能创建代理类的对象。
jdk动态代理,必须有接口,目标类必须实现接口,没有接口时,需要使用cylib动态代理。
动态代理能做什么?
可以在不改变原来目标方法功能的前提下,可以在代理中增强自己的功能代码。
程序开发中的意思。
比如:你所在的项目中,有一个功能是其他人(公司的其他部门,其他小组的人)写好的,你可以使用。
GoNong.class , GoNong gn = new GoNong(), gn,print();
你发现这个功能,现在还缺点,不能完全满足我项目的需要,我需要在gn.print()执行后,需要自己在增强代码。
用代理实现gn.print()调用时,增加自己代理,而不用去改变原来GoNang文件。
为什么要使用动态代理?
请看如下例子,一个演员的本质工作是做音乐表演、舞蹈表演、娱乐表演等,但是目前疫情管控,演出前不得不配合政府做好防疫管控。最基本的实现方法是直接对方法进行改造,添加对应的功能。
用代理模式的作用
1.功能增强 :在你原有的功能上,增强了额外的功能。新增加的功能,叫做功能增强。
2.控制访问: 代理类不让你访问目标,例如商家不让用户访问厂家。
实现代理的方式:
1.静态代理:
1)代理类是自己手工实现的,自己创建一个java类,表示代理类。
2)同时你所要代理的目标类是确定(固定)的。
特点:
- 实现简单
- 容易理解。
缺点:当你的项目中,目标类和代理类很多时候,有以下的缺点:
- 当目标类增加了,代理类可能也需要成倍的增加。代理类数量过多。
- 当你的接口中功能增加了,或者修改了,会影响众多的实现类,厂家类,代理都需要修改,影响比较大
/* 接口*/
public interface Actor {
void sing(int money);
String dance();
void rap();
}
/*实现类*/
public class Ck implements Actor {
@Override
public void sing(int money) {
System.out.println("唱"+money);
}
@Override
public String dance() {
System.out.println("街舞");
return "nick";
}
@Override
public void rap() {
System.out.println("山河志");
}
}
测试类
public class gsgc {
public static void main(String[] args) {
// 1.创建被代理类的对象
Actor c=new Ck();
// 2.创建代理对象--具体到个人
/**
*
* ClassLoader loader:类的加载器
*Class<?>[] interfaces:类的接口类型
* InvocationHandler h:处理器
*/
Actor jjr= (Actor) Proxy.newProxyInstance(Ck.class.getClassLoader(), Ck.class.getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result=null;
result=method.invoke(Ck,args);
return result;
}
});
jjr.sing(550);
}
}
2 .动态代理
在静态dialing中目标类很多时候,可以使用动态代理,避免静态代理的缺点。
动态代理中目标类即使很多,1>代理类数量可以很少 ,2>当你修改了接口中的方法时,不会影响代理类。
动态代理:在程序执行过程中,使用jdk的反射机制,创建代理类对象,并动态的指定要代理目标类。
换句话说,动态代理是一种创建java对象的能力,让你不用创建TaoBao类,就能创建代理类对象。
在java中,要想创建对象: 1)创建类文件,java文件编译为class 2)使用构造方法,创建类的对象
核心类
/*接口*/
public interface BookService {
int save(int n);
void del();
void update();
void find();
}
/*实现类内容*/
@Override
public int save(int n) {
int a=5/0;
return 1;
}
@Override
public void del() {
System.out.println("删除");
}
@Override
public void update() {
System.out.println("修改");
}
@Override
public void find() {
System.out.println("查找");
}
增强类
public class Loger {
public void check(){
System.out.println("前置通知/增强:执行系统权限验证");
}
public void logPrint(){
System.out.println("后置通知/增强:执行日志打印");
}
public void exception(){
System.out.println("异常通知/增强:做出异常处理");
}
public void distory(){
System.out.println("最终通知/增强:资源释放");
}
}
测试类
public class Text {
@Test
public void text01(){
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
BookService bean = context.getBean(BookService.class);
bean.save(1);
}
}
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: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.T.advice.Loger"/>
<bean id="bookService" class="com.T.service.Impl.BookServiceImpl"/>
<!--2.AOP的配置:让增强类 的 哪个方法 动态进行何种增强 核心类 的 哪个方法-->
<aop:config>
<aop:aspect id="log" ref="loger">
<!-- <aop:after method="check" pointcut="execution(void com.T.service.Impl.BookServiceImpl.save())"/>-->
<!-- 前置通知/增强-->
<aop:before method="check" pointcut="execution(* *..BookServiceImpl.*(..))"/>
<!-- 后置通知/增强-->
<aop:after-returning method="logPrint" pointcut="execution(* *..BookServiceImpl.*(..)))"/>
<!-- 异常通知/增强-->
<aop:after-throwing method="exception" pointcut="execution(* *..BookServiceImpl.*(..))"/>
<!-- 最终通知/增强-->
<aop:after method="distory" pointcut="execution(* *..BookServiceImpl.*(..))"/>
</aop:aspect>
</aop:config>
</beans>
Advice在Spring AOP中对应API
上面说到的Aspject中的注解,其中有五个是用来定义Advice的,表示代理逻辑,以及执行时机:
- @Before
- @AfterReturning
- @AfterThrowing
- @After
- @Around
Spring自己也提供了类似的执行实际的实现类:
- 接口MethodBeforeAdvice,继承了接口BeforeAdvice
- 接口AfterReturningAdvice
- 接口ThrowsAdvice
- 接口AfterAdvice
- 接口MethodInterceptor
Spring会把五个注解解析为对应的Advice类:
- @Before:AspectJMethodBeforeAdvice,实际上就是一个MethodBeforeAdvice
- @AfterReturning:AspectJAfterReturningAdvice,实际上就是一个AfterReturningAdvice
- @AfterThrowing:AspectJAfterThrowingAdvice,实际上就是一个MethodInterceptor
- @After:AspectJAfterAdvice,实际上就是一个MethodInterceptor
- @Around:AspectJAroundAdvice,实际上就是一个MethodInterceptor
- 接口AfterReturningAdvice
- 接口ThrowsAdvice
- 接口AfterAdvice
- 接口MethodInterceptor