目录
1.6 关于JDK代理和CGlib代理总结(高程/架构)!!!
1. 代理模式
1.1 创建项目
1.1.1创建项目
1.1.2 完成入门代码测试
1.1.3 编辑UserService
package com.jt.service;
public interface UserService {
void addUser();
}
1.1.3.2 编辑ServiceImpl实现类
package com.jt.service;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService{
@Override
public void addUser() {
System.out.println("新增用户");
}
}
1.1.4 业务层如何控制事务
事务: 可以保证数据的/原子性/一致性/持久性/隔离性.
说明: 业务层操作时,需要考虑数据库的事务.代码结构如下:
package com.jt.service;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService{
@Override
public void addUser() {
try {
System.out.println("开启数据库事务");
System.out.println("新增用户");
int a = 1/0;
System.out.println("提交数据库事务");
}catch (Exception e){
System.out.println("事务回滚");
}
}
}
1.1.4 业务代码-问题说明
- 如果有多个方法,则每个方法都需要控制事务. 代码重复率高.
- 业务层service,应该只处理业务,不要和事务代码耦合在一起.否则扩展性不好,耦合性高.
如何解决: 采用代理机制解决.
1.2 代理机制
1.2.1 代理模式特点
说明: 一般采用代理模式,主要的目的就是为了解耦.将公共的通用的方法(功能/业务)放到代理对象中. 由业务层专注于业务执行即可.
1.2.1 代理特点
- 为什么使用代理? 因为自己不方便(没有资源)
- 代理的作用? 代理要解决(扩展)某些实际问题.
- 用户最终执行目标方法!!!
1.3 动态代理-JDK模式
1.3.1 JDK代理的说明
- JDK代理模式是java原生提供的API,无需导包
- JDK代理要求: 被代理者必须 要么是接口,要么实现接口
- 灵活: 代理对象应该看起来和被代理者 一模一样!!! (方法相同)
1.3.2 编辑代理类
package com.jt.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxy {
//传入target目标对象获取代理对象的
//利用代理对象 实现方法的扩展
public static Object getProxy(Object target){
//1.获取类加载器
ClassLoader classLoader = target.getClass().getClassLoader();
//2.获取接口数组类型
Class[] interfaces = target.getClass().getInterfaces();
//3.代理对象执行方法时的回调方法(代理对象调用方法时,执行InvocationHandler)
return Proxy.newProxyInstance(classLoader,interfaces,invocationHandler(target));
}
//要求必须传递目标对象
public static InvocationHandler invocationHandler(Object target){
return new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("事务开启");
//获取目标方法的返回值
Object result = method.invoke(target,args);
System.out.println("事务提交");
return result;
}
};
}
}
1.3.3 编辑测试类
package com.jt;
import com.jt.config.SpringConfig;
import com.jt.proxy.JDKProxy;
import com.jt.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class TestSpring {
@Test
public void demo1(){
ApplicationContext context =
new AnnotationConfigApplicationContext(SpringConfig.class);
//获取目标对象
UserService userService = context.getBean(UserService.class);
//userService.addUser();
//获取代理对象
UserService proxy = (UserService) JDKProxy.getProxy(userService);
//代理对象执行方法, 调用invoke方法
proxy.addUser();
}
}
1.4 动态代理-JDK模式案例
需求: 要求大家计算addUser()方法的运行时间? 要求采用动态代理的方式完成.
1.4.1 编辑代理对象
public static Object getTimePorxy(Object target){
ClassLoader classLoader = target.getClass().getClassLoader();
Class[] interfaces = target.getClass().getInterfaces();
return Proxy.newProxyInstance(classLoader,interfaces,invocationHandlerTime(target));
}
//要求必须传递目标对象
public static InvocationHandler invocationHandlerTime(Object target){
return new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//开始时间
long startTime = System.currentTimeMillis();
//让目标方法执行 结果
Object result = method.invoke(target,args);
long endTime = System.currentTimeMillis();
System.out.println("耗时:"+(endTime - startTime));
return result;
}
};
}
1.4.2 编辑测试方法
package com.jt;
import com.jt.config.SpringConfig;
import com.jt.proxy.JDKProxy;
import com.jt.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class TestSpring {
@Test
public void demo1(){
ApplicationContext context =
new AnnotationConfigApplicationContext(SpringConfig.class);
//获取目标对象
UserService userService = context.getBean(UserService.class);
System.out.println(userService.getClass());
//userService.addUser();
//获取代理对象
UserService proxy = (UserService) JDKProxy.getTimePorxy(userService);
System.out.println(proxy.getClass());
//代理对象执行方法, 调用invoke方法
proxy.addUser();
}
}
1.5 动态代理-CGLIB代理
1.5.1 CGLIB说明
jdk代理: 要求必须有/实现接口. 如果没有接口,则JDK代理不能正常执行.
cglib代理: 要求被代理者有无接口都可以. 代理对象是目标对象的子类 重写子类方法
1.5.2 CGLIB代理模式
package com.jt.proxy;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CGlibProxy {
public static Object getProxy(Object target){
//1.创建增强器对象
Enhancer enhancer = new Enhancer();
//2.设定父级 目标对象
enhancer.setSuperclass(target.getClass());
//3.定义回调方法 代理对象执行目标方法时调用
enhancer.setCallback(getMethodInterceptor(target));
//4.创建代理对象
return enhancer.create();
}
//需要传递target目标对象
public static MethodInterceptor getMethodInterceptor(Object target){
return new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("事务开始");
//执行目标方法
Object result = method.invoke(target,args);
System.out.println("事务提交");
return result;
}
};
}
}
1 .5.3 CGLIB代理测试类
@Test
public void demo2(){
ApplicationContext context =
new AnnotationConfigApplicationContext(SpringConfig.class);
//获取目标对象
UserService userService = context.getBean(UserService.class);
UserService proxy = (UserService) CGlibProxy.getProxy(userService);
System.out.println(proxy.getClass());
proxy.addUser();
}
1.6 关于JDK代理和CGlib代理总结(高程/架构)!!!
1. JDK要求必须有或者实现接口, cglib有无接口都可以创建代理对象.代理对象是目标对象的子类
2. JDK代理工具API: Proxy.newProxyInstance(类加载器,接口数组,invocationHandler接口)
3. CGlib代理工具API: Enhancer 增强器对象 获取代理对象 enhancer.create(); 回调接口
MethodInterceptor接口
4. JDK中执行目标方法
-method.invoke(target,args);
CGlib中执行目标方法
-method.invoke(target,args);