一、代理介绍:
开始接触代理是在设计模式动态代理中了解的,大概是这样的:张三喜欢一个女孩,但是她不敢表白怎么办,很简单,他找李四帮他去表白。这里李四就是代理对象,代替张三干活,可以看下面的画面:
慢慢积累之后,发现很多经典的框架背后都使用了代理的模式,例如Spring的AOP实现原理便是动态代理;常用的ORM模型中mybatis框架实现原理也是动态代理;事务的实现原理反射+动态代理;dubbo的实现中也有动态代理…很多很多,我们可以得出的结论是熟悉代理以及熟悉动态代理的重要性。代理模式是:通过代理控制对目标对象的访问,下面是代理类图:
二、代理分类
代理分为:静态代理和动态代理;
动态代理分类:jdk动态代理和cglib动态代理。
**1.静态代理介绍**
静态代理是有实实在在的代理类存在,并且和目标类实现相同的接口。它的特点是效率高,因为所有的类都是已经编写完 成的,客户端只需要取得代理对象并且执行即可,同时他可以实现对目标对象中指定的方法进行增强。它的优缺点:
优点:效率高;
缺点:
与目标类实现相同的接口代码冗余;
如果接口发生改变,代理类中的方法也要修改;
代理类服务于一种类型的对象,如果要服务多类型的对象,那么势必要为每种类型的对象都生成代理类。
2.动态代理介绍
动态代理能用很少的代码对一个类的所有方法实现一样的增强效果,但是不能增强其中的某一个方法。与静态代理的硬编
码方式相比,动态代理支持运行时动态生成代理对象这种方式
优点:
在编码时代理逻辑与业务逻辑互相独立;
各不影响,减少侵入,降低耦合。
**jdk和cglib两种动态代理方式对比:**
*jdk
目标类和代理类实现了共同的接口;
拦截器必须实现InvocationHandler接口,而这个接口中invoke方法体的内容就是代理对象方体的内容;
当客户端用代理对象调用方法的时候,invoke方法执行。
*cglib
目标类是代理类的父类;
拦截器必须实现MethodInterceptor接口,而接口中的intercept方法就是代理类的方法体;
使用字节码增强机制创建代理对象的。
三、代理实现过程(coding…)
1.静态代理:
日志:
package com.test.spring.proxy_02proxy;
public class Logger {
public void logger(){
System.out.println(“logging”);
}
}
安全性:
package com.test.spring.proxy_02proxy;
public class Security {
public void security(){
System.out.println(“security…”);
}
}
权限:
package com.test.spring.proxy_02proxy;
public class Privilege {
private String access;
public String getAccess() {
return access;
}
public void setAccess(String access) {
this.access = access;
}
}
接口:
package com.test.spring.proxy_02proxy;
public interface SalaryManager {
public void showSalary();
}
目标类(接口的实现类):
package com.test.spring.proxy_02proxy;
public class SalaryManagerImpl implements SalaryManager{
@Override
public void showSalary() {
System.out.println(“正在查看工资:涨了20W人民币”);
}
}
代理类:
package com.test.spring.proxy_02proxy;
/**
-
1.导入日志、安全性框架和权限
-
2.目标对象
-
3.在代理对象的方法中调用上面的方法
-
*/
public class SalaryManagerProxy implements SalaryManager {
private Logger logger;
private Security security;
private Privilege privilege;
private SalaryManager targetSalaryManager;//利用构造函数赋值
public SalaryManagerProxy(Logger logger,Security security,Privilege privilege,SalaryManager targetSalaryManager){
this.logger = logger;
this.security = security;
this.privilege = privilege;
this.targetSalaryManager = targetSalaryManager;
}@Override
public void showSalary() {
this.logger.logger();
this.security.security();
if(“admin”.equals(this.privilege.getAccess())){
this.targetSalaryManager.showSalary();
}else{
System.out.println(“你没有权限查看!”);
}
}
}
客户端测试类:
package com.test.spring.proxy_02proxy;
import org.junit.Test;
public class SalaryProxyTest {
@Test
public void test(){
Logger logger = new Logger();
Privilege privilege = new Privilege();
privilege.setAccess(“admin”);
Security security = new Security();
SalaryManager targetSalaryManager = new SalaryManagerImpl();
SalaryManagerProxy salaryManagerProxy = new SalaryManagerProxy(logger,
security, privilege, targetSalaryManager);
salaryManagerProxy.showSalary();
}
}
2.动态代理:
2.1jdk动态代理
Person实例:
package com.test.spring.proxy_04jdkproxydao;
public class Person {
private Long pid;
private String pname;
public Long getPid() {
return pid;
}
public void setPid(Long pid) {
this.pid = pid;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
}
接口:
package com.test.spring.proxy_04jdkproxydao;
public interface PersonDao {
public void insertPerson();
public void updatePerson();
public void deletePerson();
}
目标类:(接口的实现类)
package com.test.spring.proxy_04jdkproxydao;
public class PersonDaoImpl implements PersonDao{
@Override
public void insertPerson() {
System.out.println(“insert Person!”);
}
@Override
public void updatePerson() {
System.out.println(“update Person!”);
}
@Override
public void deletePerson() {
System.out.println(“delete Person!”);
}
}
事务:(开启事务,提交事务)
package com.test.spring.proxy_04jdkproxydao;
public class Transaction {
public void beginTransaction(){
System.out.println(“Begin transaction!”);
}
public void commitTransaction(){
System.out.println(“Commit transaction!”);
}
}
拦截器:
package com.test.spring.proxy_04jdkproxydao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class PersonInterceptor implements InvocationHandler{
private Transaction transaction;
private Object target;
public PersonInterceptor(Transaction transaction,Object target){
this.transaction = transaction;
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object obj;
String methodName = method.getName();
if("insertPerson".equals(methodName) || "updatePerson".equals(methodName) || "deletePerson".equals(methodName)){
this.transaction.beginTransaction();//开启事务
obj = method.invoke(target, args);
this.transaction.commitTransaction();//提交事务
}else{
obj = method.invoke(target, args);
}
return obj;
}
}
客户端测试类:
package com.test.spring.proxy_04jdkproxydao;
import java.lang.reflect.Proxy;
import org.junit.Test;
/**
- 代理对象的方法:
- *就是拦截器中invoke方法体的内容
- *代理对象的方法把目标方法和切面(可以是日志、安全性的检查、权限、事务)就整合在一起了
- *代理对象的是有jdk的类库生成的
- */
public class ProxyDaoTest {
@Test
public void test(){
Transaction transaction = new Transaction();
PersonDao targerPersonDao = new PersonDaoImpl();
PersonInterceptor interceptor = new PersonInterceptor(transaction,targerPersonDao);
//代理对象Proxy,调用的方法是newProxyInstance(loader, interfaces, h)
PersonDao proxy = (PersonDao) Proxy.newProxyInstance(targerPersonDao.getClass().getClassLoader(),
targerPersonDao.getClass().getInterfaces(), interceptor);
proxy.insertPerson();
}
小总结1:
基于jdk的动态代理需要有实现的接口;
动态代理的核心:是创建了处理器 InvocationHandler实例。在调用目标对象时,会调用代理对象,代理对象中请求目标对象,invoke方法便是调用目标对象的方法生成代理对象的过程,同时增强工作也是在invoke方法中进行的。
2.2cglic动态代理
Person实例:
package com.test.spring.proxy_04jdkproxydao;
public class Person {
private Long pid;
private String pname;
public Long getPid() {
return pid;
}
public void setPid(Long pid) {
this.pid = pid;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
}
目标类:
package com.test.spring.proxy_04jdkproxydao;
public class PersonDaoImpl{
public void insertPerson() {
System.out.println(“insert Person!”);
}
public void updatePerson() {
System.out.println(“update Person!”);
}
public void deletePerson() {
System.out.println(“delete Person!”);
}
}
事务:(开启事务,提交事务)
package com.test.spring.proxy_04jdkproxydao;
public class Transaction {
public void beginTransaction(){
System.out.println(“Begin transaction!”);
}
public void commitTransaction(){
System.out.println(“Commit transaction!”);
}
}
拦截器:
package com.test.spring.proxy_05cglibproxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class PersonInterceptor implements MethodInterceptor{
private Transaction transaction;
private Object target;
public PersonInterceptor(Transaction transaction,Object target){
this.transaction = transaction;
this.target = target;
}
//创建代理
public Object createProxy(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());//设置目标类为代理类的父类
enhancer.setCallback(this);//设置拦截器为回调函数
return enhancer.create();
}
@Override
public Object intercept(Object arg0, Method method, Object[] arg2,
MethodProxy arg3) throws Throwable {
Object obj;
String methodName = method.getName();
if("insertPerson".equals(methodName) || "updatePerson".equals(methodName) || "deletePerson".equals(methodName)){
this.transaction.beginTransaction();//开启事务
obj = method.invoke(target, arg2);
this.transaction.commitTransaction();//提交事务
}else{
obj = method.invoke(target, arg2);
}
return obj;
}
}
客户端测试:
package com.test.spring.proxy_05cglibproxy;
import org.junit.Test;
public class ProxyDaoTest {
@Test
public void test(){
Transaction transaction = new Transaction();
PersonDaoImpl targerPersonDao = new PersonDaoImpl();
PersonInterceptor interceptor = new PersonInterceptor(transaction,targerPersonDao);
PersonDaoImpl proxy = (PersonDaoImpl) interceptor.createProxy();
proxy.updatePerson();
}
}
小总结2:
基于cglib的动态代理是没有实现接口的,它是以目标类作为代理类的父类
cglib动态代理的关键是基于enhancer.setCallback方法,和其中的MethodInterceptor() 方法
在MethodInterceptor实例中重写intercept方法中调用invoke方法设置代理对象,最后通过enhancer.create()创建代理对象。