1、什么是代理宝磨?
代理是一種軟件設計模式疮绷,其是通過訪問代理對象的方法翰舌,而對被代理對象進行操作,相當于加了一個中間環(huán)節(jié)冬骚。這個就好比 商戶---->明星經(jīng)紀人(代理)---->明星這種模式椅贱。我們可以不通過直接與明星對話的情況下懂算,而通過明星經(jīng)紀人(代理)與其產(chǎn)生間接對話。有些時候我們不希望修改已有代碼增加功能庇麦,這個時候就可以使用代理计技。 上網(wǎng)翻墻也是同一個意思。
2山橄、靜態(tài)代理和動態(tài)代理
我們根據(jù)加載被代理類的時機不同垮媒,將代理分為靜態(tài)代理和動態(tài)代理。如果我們在代碼編譯時就確定了被代理的類是哪一個驾胆,那么就可以直接使用靜態(tài)代理涣澡;如果不能確定,那么可以使用類的動態(tài)加載機制丧诺,在代碼運行期間加載被代理的類這就是動態(tài)代理,比如RPC框架和Spring AOP機制奄薇。
3驳阎、靜態(tài)代理
要點:
- 代理接口
- 被代理對象
- 代理對象,與被代理對象實現(xiàn)同一接口馁蒂,持有被代理對象的對象呵晚。
/**
* 描述:
*
* @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("經(jīng)紀人談好演出事宜");
System.out.println("經(jīng)紀人簽訂合約");
loudehua.show();
System.out.println("經(jīng)紀人收款");
}
@Override
public void movie() {
System.out.println("經(jīng)紀人談好演出事宜");
System.out.println("經(jīng)紀人簽訂合約");
loudehua.movie();
System.out.println("經(jīng)紀人收款");
}
}
package proxy;
/**
* 描述:
* java 動態(tài)代理
* @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、動態(tài)代理
動態(tài)代理在java中有兩種實現(xiàn)方式
- jdk動態(tài)代理
- cglib 動態(tài)代理
JDK動態(tài)代理
要點:
- 動態(tài)代理接口
- 動態(tài)代理對象
- 動態(tài)代理實現(xiàn)類沫屡。實現(xiàn)InvocationHandler接口
/**
* 描述:
* 動態(tài)代理類饵隙,實現(xiàn)InvocationHandler接口
* 動態(tài)代理的而必須是接口
* @author bigpeng
* @create 2019-12-02 23:28
*/
public class DynamicProxy implements InvocationHandler {
private Object targetObject;
public Object newInstance(Object targetObject){
this.targetObject=targetObject;
//第一個參數(shù)指定產(chǎn)生代理對象的類加載器,需要將其指定為和目標對象同一個類加載器
//第二個參數(shù)要實現(xiàn)和目標對象一樣的接口沮脖,所以只需要拿到目標對象的實現(xiàn)接口
//第三個參數(shù)表明這些被攔截的方法在被攔截時需要執(zhí)行哪個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("經(jīng)紀人談好演出事宜");
System.out.println("經(jīng)紀人簽訂合約");
Object result = method.invoke(targetObject, args);
System.out.println("經(jīng)紀人收錢");
return result;
}
}
cglib 動態(tài)代理
- 導入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 方法參數(shù)
* @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動態(tài)代理
JdkDynamicAopProxy - cglib動態(tài)代理
CglibAopProxy
區(qū)別
JDK動態(tài)代理:利用反射機制生成一個實現(xiàn)代理接口的匿名類金矛,在調用具體方法前調用InvokeHandler來處理。
CGlib動態(tài)代理:利用ASM(開源的Java字節(jié)碼編輯庫勺届,操作字節(jié)碼)開源包驶俊,將代理對象類的class文件加載進來,通過修改其字節(jié)碼生成子類來處理免姿。
區(qū)別:JDK代理只能對實現(xiàn)接口的類生成代理饼酿;CGlib是針對類實現(xiàn)代理,對指定的類生成一個子類胚膊,并覆蓋其中的方法故俐,這種通過繼承類的實現(xiàn)方式,不能代理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接口的每一個實現(xiàn)類的每一個方法開始之前執(zhí)行一段代碼
*/
@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));
}
/*
- 返回通知:在方法執(zhí)行后執(zhí)行的代碼肩榕,無論方法是否發(fā)生異常
*/
@After("declareJoinPointExpression()")
public void afterMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("The Method " + methodName + " ends with");
}
/**
- 返回通知:在方法正常結束后執(zhí)行代碼 返回通知是可以訪問到方法的返回值
- @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);
}
/**
- 在方法出現(xiàn)異常的時候會執(zhí)行代碼 可以訪問到的異常對象刚陡,且可以指定出現(xiàn)特定異常的時候才執(zhí)行通知代碼
- @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);
}
/**
- 環(huán)繞通知需要攜帶ProceedingJoinPoint類型參數(shù)
- 環(huán)繞通知類似于動態(tài)代理的全過程惩妇,ProceedingJoinPoint類型的參數(shù)可以決定是否執(zhí)行目標方法
- 且環(huán)繞通知必須要有返回值,返回值即為目標方法的返回值
- @param pjd
- @return
*/
@Around("declareJoinPointExpression()")
public Object arroundMethod(ProceedingJoinPoint pjd) {
Object result = null;
String methodName = pjd.getSignature().getName();
// 執(zhí)行目標方法
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);
}
}