代理模式
产生原因:
service层:业务处理层
业务处理层于事务控制紧紧耦合在一起,代码冗余,不便于大批量开发
1.代理模式
1).组成部分
1.要求代理者实现与被代理者相同的接口
2.在代理方法中实现功能的扩展
3.用户调用代理对象完成功能(用户认为代理就是目标对象)
1.2 静态代理
1.2.1 通过代理模式实现事务控制
角色划分:
1.目标对象target UserServiceImpl类
2.目标方法 method addUser()方法
3.代理: 实现事务控制.
4.代理对象与目标对象实现相同的接口
1.2.2 修改目标对象名称
1.2.3 编辑代理类
@Service("userService")
public class StaticProxy implements UserService {
//要求引入目标对象
@Autowired //ByType byName
//@Qualifier("target")
private UserService target;
//目的: 对原有方法进行扩展
@Override
public void addUser(User user) {
try {
System.out.println("事务开始");
target.addUser(user);
System.out.println("事务结束");
}catch (Exception e){
e.printStackTrace();
System.out.println("事务回滚");
}
}
}
1.2.4 编辑测试类
@Test
public void testStaticProxy(){
ApplicationContext context =
new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = (UserService) context.getBean("userService");
User user = new User();
user.setId(10001);
user.setName("测试代理机制");
//执行用户调用
userService.addUser(user);
}
1.3 静态代理弊端
1).静态代理只针对于某个接口 不能实现所有接口的代理 实用性较差
2).静态代理中所有的方法,都需要手动的添加事务开始/事务提交代码 代码冗余 不够简洁.
2.动态代理
2.1.1 动态代理分类
-
JDK代理:
要求: 要求目标对象必须实现接口
代理要求: 代理对象也必须实现目标对象的接口
目标对象/代理关系: 目标对象与代理对象兄弟关系. -
CGlib代理
要求: 不管目标对象是否有接口,都可以为其创建代理对象
代理要求: 要求代理对象必须继承目标对象
目标对象/代理关系: 目标对象与代理对象是父子关系
2.2.1 编辑JDK动态代理
官网API:
1.关于匿名内部类用法说明: 匿名内部类引用外部参数 要求参数必须final修饰
- 该方法标识 当代理对象执行时,"回调"该方法.
java public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {} - 目标方法执行
java result = method.invoke(target,args);
package com.jt.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//能否利用一个工厂动态为目标对象创建代理
public class JDKProxyFactory {
//要求用户传递目标对象
//关于匿名内部类用法说明: 匿名内部类引用外部参数 要求参数必须final修饰
public static Object getProxy(final Object target){
//1.调用java API实现动态代理
/**
* 参数分析: 3个参数
* 1.ClassLoader loader, 类加载器(获取目标对象的Class)
* 2.类<?>[] interfaces, JDK代理要求 必须有接口
* java中可以多实现
* 3.InvocationHandler h 对目标方法进行扩展
*/
//1.获取类加载器
ClassLoader classLoader = target.getClass().getClassLoader();
//2.获取接口数组
Class[] interfaces = target.getClass().getInterfaces();
//3.通过动态代理创建对象
Object proxy = Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
//invoke方法: 代理对象调用方法时invoke执行,扩展方法的编辑位置
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// result 标识目标方法执行的返回值
Object result = null;
try {
//添加事务的控制
System.out.println("事务开始");
//执行目标方法
// target真实的目标对象,method方法对象,args方法参数
result = method.invoke(target,args);
System.out.println("事务提交");
}catch (Exception e){
e.printStackTrace();
System.out.println("事务回滚");
}
return result;
}
});
return proxy;
}
}
2.2.2 JDK动态代理执行过程
2.2.3 动态代理优势
将公共的部分写到动态代理中,之后其他的业务类调用即可
2.2.4 动态代理具体案例
1).编辑DeptService/DeptServiceImpl(目标对象)
package com.jt.vo;
public interface DeptService {
void addDept();
}
package com.jt.vo;
import com.jt.pojo.User;
import org.springframework.stereotype.Service;
@Service("target")
public class DeptServiceImpl implements DeptService {
@Override
public void addDept( ) {
System.out.println("新增用户");
}
}
2).编辑JDKProxyFactory(动态代理类)
package com.jt.vo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//编辑JDK动态代理
public class JDKProxyFactory {
public static Object getProxy(final Object target){
//1.调用java API实现动态代理
/**
* 参数分析: 3个参数
* 1.ClassLoader loader, 类加载器(获取目标对象的Class)
* 2.类<?>[] interfaces, JDK代理要求 必须有接口
* java中可以多实现
* 3.InvocationHandler h 对目标方法进行扩展
*/
//1.获取类加载器
ClassLoader classLoader = target.getClass().getClassLoader();
//2.获取接口数组
Class[] interfaces = target.getClass().getInterfaces();
//3.通过动态代理创建对象
Object proxy = Proxy.newProxyInstance(classLoader,interfaces, new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
Object result = null;
try {
//添加事务的控制
System.out.println("事务开始");
//执行目标方法
// target真实的目标对象,method方法对象,args方法参数
result= method.invoke(target,objects);
System.out.println("事务结束");
}catch (Exception e){
e.printStackTrace();
}
return result;
}
});
return proxy;
}
}
3),编辑SpringConfig配置类
package com.jt.vo;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.jt.vo")
public class SpringConfig {
}
3).编辑测试类
package com.jt.vo;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class TestJDK {
@Test
public void testProxy(){
ApplicationContext context= new AnnotationConfigApplicationContext(SpringConfig.class);
//1.获取目标对象
DeptService target= (DeptService) context.getBean("target");
//2.获取代理对象
DeptService deptService= (DeptService) JDKProxyFactory.getProxy(target);
System.out.println(deptService.getClass());
//3.调用业务方法
deptService.addDept();
}
}
4)查看测试结果
2.3 CCGLIB动态代理
CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,
它可以在运行期扩展Java类与实现Java接口。Hibernate用它来实现PO(Persistent Object 持久化对象)字节码的动态生成。
CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP为他们提供
方法的interception(拦截)。CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。
2.3.1.动态代理案例
1)实现一个业务类,注意,这个业务类并没有实现任何接口:
package com.jt.vo.cglib;
public class HelloService {
public HelloService() {
System.out.println("HelloService构造");
}
/**
* 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的
*/
final public String sayOthers(String name) {
System.out.println("HelloService:sayOthers>>" + name);
return null;
}
public void sayHello() {
System.out.println("HelloService:sayHello");
}
}
2)自定义MethodInterceptor:
package com.jt.vo.cglib;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 自定义MethodInterceptor
*/
class MyMethodInterceptor implements MethodInterceptor{
/**
* sub:cglib生成的代理对象
* method:被代理对象方法
* objects:方法入参
* methodProxy: 代理方法
*/
@Override
public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("======插入前置通知======");
Object object = methodProxy.invokeSuper(sub, objects);
System.out.println("======插入后者通知======");
return object;
}
}
3)生成CGLIB代理对象调用目标方法:
package com.jt.vo.cglib;
import org.junit.Test;
import org.springframework.cglib.core.DebuggingClassWriter;
import org.springframework.cglib.proxy.Enhancer;
public class Client {
@Test
public void testCGlib(){
// 代理类class文件存入本地磁盘方便我们反编译查看源码
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code");
// 通过CGLIB动态代理获取代理对象的过程
Enhancer enhancer = new Enhancer();
// 设置enhancer对象的父类
enhancer.setSuperclass(HelloService.class);
// 设置enhancer的回调对象
enhancer.setCallback(new MyMethodInterceptor());
// 创建代理对象
HelloService proxy= (HelloService)enhancer.create();
// 通过代理对象调用目标方法
proxy.sayHello();
}
}
4)运行结果