1、什么是代理?
代理是一种软件设计模式,其是通过访问代理对象的方法,而对被代理对象进行操作,相当于加了一个中间环节。这个就好比 商户---->明星经纪人(代理)---->明星这种模式。我们可以不通过直接与明星对话的情况下,而通过明星经纪人(代理)与其产生间接对话。有些时候我们不希望修改已有代码增加功能,这个时候就可以使用代理。 上网翻墙也是同一个意思。
2、静态代理和动态代理
我们根据加载被代理类的时机不同,将代理分为静态代理和动态代理。如果我们在代码编译时就确定了被代理的类是哪一个,那么就可以直接使用静态代理;如果不能确定,那么可以使用类的动态加载机制,在代码运行期间加载被代理的类这就是动态代理,比如RPC框架和Spring AOP机制。
3、静态代理
要点:
- 代理接口
- 被代理对象
- 代理对象,与被代理对象实现同一接口,持有被代理对象的对象。
/**
* 描述:
*
* @author bigpeng
* @create 2019-12-02 23:05
*/
public interface Star {
void show();
void movie();
}
/**
* 描述:
*
* @author bigpeng
* @create 2019-12-02 23:06
*/
public class Loudehua implements Star {
@Override
public void show() {
System.out.println("刘德华开个人演唱会");
}
@Override
public void movie() {
System.out.println("刘德华出演电影");
}
}
package proxy;
/**
* 描述:
*
* @author bigpeng
* @create 2019-12-02 23:09
*/
public class LoudehuaProxy implements Star{
private Star loudehua;
public LoudehuaProxy(Star loudehua){
this.loudehua=loudehua;
}
@Override
public void show() {
System.out.println("经纪人谈好演出事宜");
System.out.println("经纪人签订合约");
loudehua.show();
System.out.println("经纪人收款");
}
@Override
public void movie() {
System.out.println("经纪人谈好演出事宜");
System.out.println("经纪人签订合约");
loudehua.movie();
System.out.println("经纪人收款");
}
}
package proxy;
/**
* 描述:
* java 动态代理
* @author bigpeng
* @create 2019-12-02 23:15
*/
public class Test {
public static void main(String[] args) {
Star star=new Loudehua();
// Star star=new LoudehuaProxy();
// star.show();
// star.movie();
DynamicProxy dynamicProxy=new DynamicProxy();
Star o = (Star) dynamicProxy.newInstance(star);
o.movie();
o.show();
}
}
4、动态代理
动态代理在java中有两种实现方式
- jdk动态代理
- cglib 动态代理
JDK动态代理
要点:
- 动态代理接口
- 动态代理对象
- 动态代理实现类。实现InvocationHandler接口
/**
* 描述:
* 动态代理类,实现InvocationHandler接口
* 动态代理的而必须是接口
* @author bigpeng
* @create 2019-12-02 23:28
*/
public class DynamicProxy implements InvocationHandler {
private Object targetObject;
public Object newInstance(Object targetObject){
this.targetObject=targetObject;
//第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
//第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口
//第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
return Proxy.newProxyInstance(
targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(),
this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("经纪人谈好演出事宜");
System.out.println("经纪人签订合约");
Object result = method.invoke(targetObject, args);
System.out.println("经纪人收钱");
return result;
}
}
cglib 动态代理
- 导入cglibjar包
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.12</version>
</dependency>
- 如果使用spring,则配置使用cglib
<aop:aspectj-autoproxy proxy-target-class="true"/>
被代理类
/**
* 描述:
*
* @author bigpeng
* @create 2019-12-03 13:32
*/
public class Star {
public void move(){
System.out.println("参演电影");
}
}
代理类
/**
* 描述:
*
* @author bigpeng
* @create 2019-12-03 13:32
*/
public class StarProxy implements MethodInterceptor {
/**
* 提供代理对象
* @param object
* @return
*/
public Object newInstance(Object object){
return Enhancer.create(object.getClass(), this);
}
/**
*
* @param o 被代理的对象
* @param method 被代理的方法
* @param objects 方法参数
* @param methodProxy 代理方法
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println(method.getName());
System.out.println("签合同");
Object invoke = methodProxy.invokeSuper(o, objects);
System.out.println("收钱");
return invoke;
}
}
测试类
/**
* 描述:
*
* @author bigpeng
* @create 2019-12-03 13:35
*/
public class Test {
public static void main(String[] args) {
StarProxy starProxy=new StarProxy();
Star o = (Star) starProxy.newInstance(new Star());
o.move();
}
}
spring AOP源码:
- jdk动态代理
JdkDynamicAopProxy - cglib动态代理
CglibAopProxy
区别
JDK动态代理:利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
CGlib动态代理:利用ASM(开源的Java字节码编辑库,操作字节码)开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
区别:JDK代理只能对实现接口的类生成代理;CGlib是针对类实现代理,对指定的类生成一个子类,并覆盖其中的方法,这种通过继承类的实现方式,不能代理final修饰的类
spring 注解式AOP
## 注解方式配置AOP
<context:component-scan base-package="spring.aop"></context:component-scan>
<aop:aspectj-autoproxy/>
package spring.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
描述:
@author bigpeng
-
@create 2019-10-25 13:25
*/
@Component
@Aspect
public class AopAspect {/*
- 定义一个方法,用于声明切入点的表达式,一般地,该方法中不需要添加其他代码
- 使用@Pointcut来声明切入点表达式
- 后面的其他通知直接使用方法名来引用切入点表达式
/
@Pointcut("execution( spring.aop.Impl.(..))")
public void declareJoinPointExpression(){}
/*- 在top.cheungchingyin.spring.aop.
- ArithmeticCalculator接口的每一个实现类的每一个方法开始之前执行一段代码
*/
@Before("declareJoinPointExpression()")
public void beforeMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("The Method " + methodName + " Begins with " + Arrays.asList(args));
}
/*
- 返回通知:在方法执行后执行的代码,无论方法是否发生异常
*/
@After("declareJoinPointExpression()")
public void afterMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("The Method " + methodName + " ends with");
}
/**
- 返回通知:在方法正常结束后执行代码 返回通知是可以访问到方法的返回值
- @param joinPoint
*/
@AfterReturning(value = "declareJoinPointExpression()", returning = "result")
public void afterReturningMethod(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
System.out.println("The Method " + methodName + " ends with " + result);
}
/**
- 在方法出现异常的时候会执行代码 可以访问到的异常对象,且可以指定出现特定异常的时候才执行通知代码
- @param joinPoint
- @param ex
*/
@AfterThrowing(value = "declareJoinPointExpression()", throwing = "ex")
public void afterThrowing(JoinPoint joinPoint, Exception ex) {
String methodName = joinPoint.getSignature().getName();
System.out.println("The Method " + methodName + " occurs with " + ex);
}
/**
- 环绕通知需要携带ProceedingJoinPoint类型参数
- 环绕通知类似于动态代理的全过程,ProceedingJoinPoint类型的参数可以决定是否执行目标方法
- 且环绕通知必须要有返回值,返回值即为目标方法的返回值
- @param pjd
- @return
*/
@Around("declareJoinPointExpression()")
public Object arroundMethod(ProceedingJoinPoint pjd) {
Object result = null;
String methodName = pjd.getSignature().getName();
// 执行目标方法
try {
// 前置通知
System.out.println("【Around】The method 【" + methodName + "】 begins with" + Arrays.asList(pjd.getArgs()));
result = pjd.proceed();
// 后置通知
System.out.println("【Around】The Method " + " ends with 【" + result + "】");
} catch (Throwable e) {
// 异常通知
System.out.println("The method occurs exception" + e);
}
// 后置通知
System.out.println("【Around】The Method 【" + methodName + "】 ends ");
return result;
}
}
/**
* @author bigpeng
* @create 2020-06-28-19:58
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Delete {
String value();
}
package proxy;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
/**
* @author bigpeng
* @create 2020-06-28-20:02
*/
public class MapperProxy implements InvocationHandler {
public Object getMapper(Class mapper){
return Proxy.newProxyInstance(mapper.getClassLoader(),new Class[]{mapper},this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Delete delete = method.getAnnotation(Delete.class);
if(delete!=null){
String sql = delete.value();
sql = sql.replaceAll("#\\{\\w+\\}", "?");
Class.forName("oracle.jdbc.OracleDriver");
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "blog",
"123456");
PreparedStatement pstm = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
pstm.setObject(i+1,args[i]);
}
int i = pstm.executeUpdate();
return i;
}
return null;
}
}
public interface UserDao {
@Delete("delete from t_admin where id=#{id}")
int delete(int id);
}
public class Test {
public static void main(String[] args) {
String sql = "delete from t_admin where name=#{name} and id=#{id}";
String s = sql.replaceAll("#\\{\\w+\\}", "?");
System.out.println(s);
MapperProxy mapperProxy=new MapperProxy();
UserDao mapper = (UserDao) mapperProxy.getMapper(UserDao.class);
int delete = mapper.delete(21);
}
}