反射機(jī)制
Java反射機(jī)制就是在運(yùn)行狀態(tài)中整慎,對于任意一個(gè)類(class文件)声诸,都能夠知道這個(gè)類的所有屬性和方法酱讶;
對于任意一個(gè)對象,都能夠調(diào)用它的任意一個(gè)方法和屬性双絮;
對于這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對象的方法和功能稱為Java語言的反射機(jī)制浴麻。
簡述:動(dòng)態(tài)獲取類中的信息,就是Java反射
反射機(jī)制實(shí)現(xiàn)
要想對字節(jié)碼文件進(jìn)行解剖囤攀,必須要有字節(jié)碼文件對象
-
獲取字節(jié)碼對象的方式一:
-
Object類中的getClass方法:
Person p = new Person(); Class clazz = p.getClass()
-
-
獲取字節(jié)碼對象的方式二:
-
任何數(shù)據(jù)類型都具備一個(gè)靜態(tài)的屬性.class來獲取Class對象:
Class clazz = Person.class
-
-
獲取字節(jié)碼對象的方式三:
-
通過forName()方法實(shí)現(xiàn):
String className = "com.zimo.Person"; Class clazz =Class.forName(className)
-
public static void main(String args[]){
// 無參構(gòu)造
// 原方法--
com.zimo.Person p = new com.zimo.Person();
// 反射--
String className = "com.zimo.Person";
Class clazz =Class.forName(className);
clazz.newInstance();
--------------------------------------------------------------------------------------------
// 有參構(gòu)造
// 原方法--
com.zimo.Person p = new com.zimo.Person("zimo", 18);
// 反射--
String className = "com.zimo.Person";
Class clazz =Class.forName(className);
// 先獲取構(gòu)造函數(shù)列表
Constructor c = clazz.getConstructor(String.class, int.class);
// 通過構(gòu)造器的newInstance方法進(jìn)行對象的初始化
Object obj = c.newInstance("zimo", 18);
--------------------------------------------------------------------------------------------
// 獲取字節(jié)碼文件中的字段
Class clazz =Class.forName("com.zimo.Person");
Filed filed = clazz.getFiled("age"); // 只能獲取公共,私有的無法獲取
filed = clazz.getDeclaredFiled("age"); // 只能獲取本類焚挠,但包含私有
// 對私有字段的訪問取消權(quán)限檢查:暴力訪問
filed.setAccessible(true);
Object o = clazz.newInstance();
filed.set(o, 86);
Object obj = filed.get(o);
--------------------------------------------------------------------------------------------
// 獲取字節(jié)碼文件中的公共方法
Class clazz =Class.forName("com.zimo.Person");
Method[] me = clazz.getMethods(); // 獲取的都是共有的方法
Method[] me1 = clazz.getDeclaredMethods(); // 獲取本類中私有方法
Method me2 = clazz.getMethod("show", null); // 獲取person類中的show方法膏萧,空參數(shù)列表
Method me3 = clazz.getMethod("show1", String.class, int.class); // 獲取person類中的show方法,有參函數(shù)
// 運(yùn)行show方法
Object obj = clazz.newInstance();
me2.invoke(obj, null);
me3.invoke(obj, "zimo", 18);
}
反射練習(xí)
- 電腦運(yùn)行
package com.zimo.ComputerRun;
// 主板
public class MainBoard{
public void run(){
System.out.println("MainBoard Run ...........");
}
public void usePCI(PCI p){
if(p != null){
p.open();
p.close();
}
}
}
package com.zimo.ComputerRun;
/**
* 電腦運(yùn)行
*/
public class ReflectTest{
public static void main(String args[]){
MainBoard mb = new MainBoard();
mb.run();
// mb.usePCI(null);
// mb.usePCI(new SourceCard()); // 每次添加一個(gè)設(shè)備蝌衔,就需要修改代碼傳遞一個(gè)新創(chuàng)建的對象
// 不用new對象榛泛,只獲取其class文件,內(nèi)部創(chuàng)建對象:使用配置文件讀取
File configFile = new File("pci.properties");
Properties prop = new Properties();
FileInputStream fis = new FileInputStream(configFile);
prop.load(fis);
for(int i= 0;i < prop.size(); i++){
String pciName = prop.getProperty("pci" + (i + 1));
Class clazz = Class.forName(pciName); // 用Class去加載這個(gè)pci子類
PCI p = (PCI)clazz.newInstance();
mb.usePCI(p);
}
}
}
package com.zimo.ComputerRun;
public interface PCI{
public void open();
public void close();
}
#pci.properties
# 配置聲卡
pci1=com.zimo.Computer.SoundCard
# 配置網(wǎng)卡
pci2=com.zimo.Computer.NetCard
package com.zimo.ComputerRun;
// 聲卡
public class SourceCard implements PCI{
public void open(){
System.out.println("sound open...");
}
public void close(){
System.out.println("sound close...");
}
}
package com.zimo.ComputerRun;
// 網(wǎng)卡
public class NetCard {
public void open(){
System.out.println("NetCard open...");
}
public void close(){
System.out.println("NetCard close...");
}
}
- 模擬MyBatis存儲(chǔ)任何對象數(shù)據(jù)
public class Mybatis{
// 提供一個(gè)方法:可以保存任何對象數(shù)據(jù)的字段和具體值
public static void save(Object obj) throws Exception{
PrintStream ps = new PrintStream(new FileOutputStream("./data.txt", true));
// 解析對象的字段和每個(gè)字段的值存儲(chǔ)起來 obj = Student/Pig/Teacher....
// 1.先得到對象的Class文件對象
Class c = obj.getClass();
// 2.定位它的全部成員變量
Field[] fields = c.getDeclaredFields();
// 3.遍歷這些字段并取值
for(Field field : fields){
// 取字段名
String name = field.getName();
// 取字段值
field.setAccessible(true); // 暴力反射 取消訪問權(quán)限
String value = field.get(obj) + "";
ps.println(name + "=" + value);
}
ps.close();
}
}
public static void main(String args[]){
Student s = new Student(1, "zimo", "18", "秋名山", "10086");
Mybatis.save(s);
Pig p = new Pig("佩奇", 500.0, "粉色", "小紅", "母豬");
Mybatis.save(p);
}
反射適合做通用技術(shù)框架的底層實(shí)現(xiàn)噩斟,在框架底層源碼我們經(jīng)巢芟牵可以看到反射的影子
正則表達(dá)式
本身也是一個(gè)對象,java.util.regex包中(Pattern類)剃允,主要用于操作字符串沛简,通過特定的符號來體現(xiàn)的。
特點(diǎn):
- 傳統(tǒng)QQ號檢測方法:
// 需求:定義一個(gè)功能對QQ號進(jìn)行校驗(yàn)
// 要求:長度5-15椒楣,只能是數(shù)字,0不能開頭
public static void checkQQ(String qq){
int len = qq,length();
if(len >=5 && len <= 15){
if(!qq.startsWith("0")){
try{
long l = Long.parseLong(qq);
System.out.println(l + ":正確");
}catch(NumberFormatException e){
System.out.println(qq + ":含有非法字符");
}
}else{
System.out.println(qq + ":開頭不能為0");
}
}else{
System.out.println(qq + ":長度錯(cuò)誤");
}
}
- 使用正則表達(dá)式檢測QQ方法:
public static boolean checkQQByRegex(String qq){
String regex = "[1-9][0-9]{4,14}";
boolean b = qq.matches(regex);
System.out.println(b);
return b;
}
public static void main(String args[]){
String QQ = "123456";
checkQQ(QQ);
checkQQByRegex(QQ);
}
正則表達(dá)式對字符串常見操作
- 匹配:
- 其實(shí)使用的就是String類中的matches()方法
- 切割:
- 其實(shí)使用的就是String類中的split()方法
- 替換:
- 其實(shí)使用的就是String類中的replaceAll()方法
- 獲饶等狻:
- 其實(shí)使用的就是String類中的get()方法
/**
* 演示匹配
*/
public static void matchesRegex(){
// 匹配手機(jī)號碼是否正確
String tel = "15800001111";
String regex = "1[3578][0-9]{9}"; // 等價(jià)于:"1[3578]\\d{9}"
boolean b = tel.matches(regex);
System.out.println(tel + ":" + b);
}
/**
* 演示切割
*/
public static void sqlitRegex(){
// 切割疊詞姓名
String names = "zimo---zhangsan@@@@lisi######wangwu";
// String[] names = str.split(" "); // 只能切割單個(gè)空格
String[] names = names.split("(.)\\1+"); // (.)\\1 封裝成第一組
System.out.println(tel + ":" + b);
}
/**
* 演示替換
*/
public static void replaceAllRegex(){
String str = "";
str = str.replaceAll("(.)\\1+","$1"); // 用$引用前一個(gè)組中的數(shù)據(jù) zimo-zhangsan@lisi#wangwu
System.out.println(tel + ":" + b);
// 隱藏手機(jī)號158****1111
String tel = "15800001111";
tel = tel.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"); // 158****1111
}
/**
* 演示獲取
* 正則封裝成對象捧灰,創(chuàng)建一個(gè)匹配器對象,按照表達(dá)式匹配字符序列统锤,將結(jié)果留在匹配器中
*/
public static void sqlitRegex(){
String str = "da jia hao, ming tian bu fang jia!";
String regex = "\\b[a-z]{3}\\b";
// 將正則規(guī)則進(jìn)行封裝
Pattern p = Pattern.compile(regex);
// 通過正則對象的matcher方法字符串相關(guān)聯(lián)毛俏。獲取要對字符串操作的匹配器對象Matcher
Matcher m = p.matcher(p);
// 通過Matcher匹配器的對象方法對字符串進(jìn)行操作
while(m.find()){
System.out.println(m.group()); // 獲取匹配的子序列
System.out.println(m.start() + ":" + m.end()); // 獲取匹配的子序列腳標(biāo)
}
}
- 練習(xí):
// 治療口吃:我我...我我要..要要要要...要要學(xué)學(xué)學(xué)..學(xué)學(xué)學(xué)學(xué)編編編編...編編程程程程....程程程程程程程程
// ip地址排序
// 對郵件地址校驗(yàn)
public static void main(String args[]){
fun1();
}
// 治療口吃
public static void fun1(){
String str = "我我...我我要..要要要要...要要學(xué)學(xué)學(xué)..學(xué)學(xué)學(xué)學(xué)編編編編...編編程程程程....程程程程程程程程";
// 將字符串中點(diǎn)去掉,替換
str = str.replaceAll("\\.+", ""); // 我我我我要要要要要要要學(xué)學(xué)學(xué)學(xué)學(xué)學(xué)學(xué)編編編編編編程程程程程程程程程程程程
// 替換疊詞
str = str.replaceAll("(.)\\1+", "$1"); // 我要學(xué)編程
}
// ip地址排序 192.168.1.82 127.0.0.1 3.3.3.3 105.70.11.55
public static void fun2(){
String ip_str = "192.168.1.82 127.0.0.1 3.3.3.3 105.70.11.55";
// 為了讓ip可以按字符串比較饲窿,只要讓ip每段的數(shù)位相同煌寇,補(bǔ)兩個(gè)0操作
ip_str = ip_str.replaceAll("(\\d+)","00$1");
// 每一段保留三位
ip_str = ip_str.replaceAll("0*(\\d{3})","$1");
// 將ip地址切出
String[] ips = ip_str.split(" +");
// 排序
TreeSet<String> ts = new TreeSet<String>();
for(String ip : ips){
ts.add(ip);
}
for(String ip : ts){
System.out.println(ip.replaceAll("0*(\\d+)", "$1"));
}
}
// 對郵件地址校驗(yàn)
public static void fun3(){
String mail = "abc1@sina.com";
String regex = "[a-zA-Z0-9_]+@[a-zA-Z0-9]+(\\.[a-zA-Z]{1,3}){1,3}";
regex = "\\w+@\\w+(\\.\\w+)+"; // 可以匹配 1@1.1
boolean b = mail.matches(regex);
System.out.println(mail + ":" + b);
}
網(wǎng)頁爬蟲
用于在互聯(lián)網(wǎng)中獲取符合指定規(guī)則的數(shù)據(jù)
// 爬取郵箱地址
public static void main(String args[]){
List<String> list = getMails();
for(String l : list){
System.out.println(l);
}
}
// 爬取本地?cái)?shù)據(jù)
public static List<String> getMails(){
// 讀取源文件
BufferedReader bufr = new BufferedReader(new FileReader("D:\\mail.html"));
// 對讀取的數(shù)據(jù)進(jìn)行規(guī)則的匹配,從中獲取符合規(guī)則的數(shù)據(jù)
String mail_regex = "\\w+@\\w+(\\.\\w+)+";
List<String> list = new ArrayList<String>();
Pattern p = Pattern.compile(mail_regex);
String line = null;
while((line = bufr.readLine())!=null){
Matcher m = p.matcher(line);
while(m.find()){
// 將符合規(guī)則的數(shù)據(jù)存儲(chǔ)到集合中
list.add(m.group());
}
}
return list;
}
// 爬取本地?cái)?shù)據(jù)
public static List<String> getMailsByWeb(){
// 讀取源文件
// BufferedReader bufr = new BufferedReader(new FileReader("D:\\mail.html"));
URL url = new URL("http://192.168.1.82:8080/myweb/mail.html");
BufferedReader bufr = new BufferedReader(new InputStreamReader(url.openStream()));
// 對讀取的數(shù)據(jù)進(jìn)行規(guī)則的匹配免绿,從中獲取符合規(guī)則的數(shù)據(jù)
String mail_regex = "\\w+@\\w+(\\.\\w+)+";
List<String> list = new ArrayList<String>();
Pattern p = Pattern.compile(mail_regex);
String line = null;
while((line = bufr.readLine())!=null){
Matcher m = p.matcher(line);
while(m.find()){
// 將符合規(guī)則的數(shù)據(jù)存儲(chǔ)到集合中
list.add(m.group());
}
}
return list;
}
單元測試框架
org.junit測試框架的使用
package SectionTestDemo;
import org.junit.Assert;
import org.junit.Test;
public class UserServiceTest {
/**
* 測試方法的要求:
* 1. public 修飾
* 2. 沒有返回值沒有參數(shù)
* 3. 必須使用@Test修飾
*/
@Test
public void testLogin(){
UserService userService = new UserService();
String rs = userService.login("admin", "123456");
// 預(yù)期斷言結(jié)果正確性
Assert.assertEquals("err", "success", rs);
}
}
/**
* org.junit.ComparisonFailure: err
* 期望:success
* 實(shí)際:error
* 紅色:err 綠色:ok
*/
package SectionTestDemo;
public class UserService {
public String login(String name, String pass){
if ("admin".equals(name) && "1234567".equals(pass)){
return "success";
}else {
return "error";
}
}
}
注解說明:
- @Test:測試方法
- @Before:測試實(shí)例方法之前 Junit 5:使用的是BeforeEach
- @After:測試實(shí)例方法之后 Junit 5:使用的是AfterEach
- @BeforeClass:測試靜態(tài)方法之前 Junit 5:使用的是BeforeAll
- @AfterClass:測試靜態(tài)方法之后 Junit 5:使用的是AfterAll
注解
- 用在類上唧席,方法上,成員變量,構(gòu)造器淌哟,.... 上對成分進(jìn)行編譯約束迹卢,標(biāo)記等操作的。
- 注解是JDK1.5的新特性徒仓。
- 注解相當(dāng)一種標(biāo)記腐碱,是類的組成部分,可以給類攜帶一些額外的信息掉弛。
- 注解是給編譯器或JVM看的症见,編譯器或JVM可以根據(jù)注解來完成對應(yīng)的功能。
注解作用
- 標(biāo)記殃饿。
- 方法重寫約束@Override
- 函數(shù)式接口約束谋作。@FunctionalInterface.
- 現(xiàn)今最牛逼的框架技術(shù)多半都是在使用注解和反射。都是屬于框架的基礎(chǔ)技術(shù)乎芳。
自定義注解
-
自定義注解格式:
修飾符 @interface 注解名{
注解屬性
}
-
小結(jié):
- 自定義注解使用@interface關(guān)鍵字
- 注解默認(rèn)可以標(biāo)記很多地方
package com.zimo._01selfNote;
@interface Book{
}
@interface MyTest{
}
@Book
public class MyBook {
@Book
@MyTest
public static void main(@MyTest String[] args) {
@MyTest
int age = 12;
}
}
-
注解屬性格式:
- 格式1:
數(shù)據(jù)類型 屬性名()
- 格式2:
數(shù)據(jù)類型 屬性名() default 默認(rèn)值
- 格式1:
-
屬性使用的數(shù)據(jù)類型:
八種基礎(chǔ)數(shù)據(jù)類型(int遵蚜,short,long奈惑,double吭净,byte,char肴甸,boolean寂殉,float)
String,Class
以上類型都支持
-
小結(jié):
- 注解可以有屬性原在,屬性名必須帶()
- 在用注解的時(shí)候友扰,屬性必須賦值,除非這個(gè)屬性有默認(rèn)值N钫丁焕檬!
package com.zimo._01selfNote;
@interface Book{
// 不寫默認(rèn)public
String name();
String[] authors();
double price();
String address() default "中國-北京";
}
@Book(name = "《精通Java基礎(chǔ)》",authors = {"zimo","mike"}, price = 59.9)
public class MyBook {
@Book(name = "《SQL從入門到放棄》",authors = {"小白","遞歸"}, price = 9.99, address = "中國-上海")
public static void main(String[] args) {
}
}
- 注解的特殊屬性名稱:value
- value屬性姆坚,如果只有一個(gè)value屬性的情況下澳泵,使用value屬性的時(shí)候可以省略value名稱不寫!兼呵!
- 如果有多個(gè)屬性兔辅,且多個(gè)屬性沒有默認(rèn)值,那么value是不能省略的
package com.zimo._02zhujie;
@interface Book{
String value();
}
@interface Book1{
String value();
int age();
}
@interface Book2{
String value();
int age() default 18;
}
//@Book(value = "delete.action")
@Book("delete.action") // 可省略value不寫
public class MyBook {
}
@Book1(value = "delete.action", age = 12) // 有多個(gè)必須全寫
@Book2("delete.action") // 若多個(gè)值都有默認(rèn)值
class MyBook1 {
}
元注解
元注解是sun公司提供的击喂,是用在自定義注解上的注解维苔,是用來注解自定義注解的
-
元注解有兩個(gè):
-
@Target:約束自定義注解只能在那些地方使用
但是默認(rèn)的注解可以在類,方法懂昂,構(gòu)造器介时,成員變量,......使用
ElementType:
- TYPE // 類、接口沸柔、枚舉類
- FIELD // 成員變量(包括:枚舉常量)
- METHOD // 成員方法
- PARAMETER // 方法參數(shù)
- CONSTRUCTOR // 構(gòu)造方法
- LOCAL_VARIABLE // 局部變量
- ANNOTATION_TYPE // 注解類
- PACKAGE // 可用于修飾:包
- TYPE_PARAMETER // 類型參數(shù)循衰,JDK 1.8 新增
- TYPE_USE // 使用類型的任何地方,JDK 1.8 新增
-
@Retention:聲明注解的生命周期
聲明注解的作用范圍:編譯時(shí)褐澎,運(yùn)行時(shí)
RetentionPolicy:
- SOURCE // 源文件保留
- CLASS // 編譯期保留会钝,默認(rèn)值
- RUNTIME // 運(yùn)行期保留,可通過反射去獲取注解信息工三,開發(fā)常用
-
注解的解析
package com.zimo._04_ReNote;
import org.junit.Test;
import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.util.Arrays;
@Target({ElementType.TYPE,ElementType.METHOD}) // 類和方法使用
@Retention(RetentionPolicy.RUNTIME) // 永久存活
@interface Book{
String value();
double price() default 100;
String[] author();
}
@Book(value = "《Java基礎(chǔ)》",price = 99.9, author = {"zimo","mike"})
class BookStore{
@Book(value = "《MyBatis持久層框架》",price = 199.9, author = {"zimo","jack"})
public void run(){
}
}
public class ReNote {
@Test
public void parseClass(){
// 解析注解
// 1.定位Class類對象
Class c = BookStore.class;
// 2.判斷類上是否使用了某個(gè)注解
if (c.isAnnotationPresent(Book.class)){
// 3.獲取注解對象
Book book = (Book) c.getDeclaredAnnotation(Book.class);
System.out.println(book.value() + book.price() + Arrays.toString(book.author())); // java基礎(chǔ)
}
// 1.1 定位方法對象
Method run = c.getDeclaredMethod("run");
// 1.2
if (run.isAnnotationPresent(Book.class)){
// 1.3 獲取注解對象
Book book = (Book) c.getDeclaredAnnotation(Book.class);
System.out.println(book.value() + book.price() + Arrays.toString(book.author())); // mybatis
}
}
}
模擬Junt.Test方法
package com.zimo._05_MyTest;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
@Target(ElementType.METHOD) // 方法使用
@Retention(RetentionPolicy.RUNTIME)
@interface MyTest{
}
public class MyTestDemo {
@MyTest
public void test01(){
System.out.println("1111");
}
public void test02(){
System.out.println("2222");
}
@MyTest
public void test03(){
System.out.println("3333");
}
public static void main(String[] args) throws Exception{
// 模擬測試類啟動(dòng)按鈕
MyTestDemo myTestDemo = new MyTestDemo();
// 1.得到類對象
Class c = MyTestDemo.class;
// 2.獲取類全部方法對象
Method[] methods = c.getDeclaredMethods();
// 3.遍歷全部方法
for (Method method : methods) {
if (method.isAnnotationPresent(MyTest.class)){
// 運(yùn)行此方法
method.invoke(myTestDemo);
}
}
}
}
動(dòng)態(tài)代理
動(dòng)態(tài)代理設(shè)計(jì)模式(讓別人替我們?nèi)プ瞿承┦拢?/p>
動(dòng)態(tài)代理只能為實(shí)現(xiàn)接口的實(shí)現(xiàn)類對象做代理(也可以只為接口做代理對象)
- 開發(fā)步驟:
- 必須有接口
- 實(shí)現(xiàn)類要實(shí)現(xiàn)接口迁酸,定義自己的業(yè)務(wù)功能代碼
- 為業(yè)務(wù)功能做代理對象(動(dòng)態(tài)代理)
- 小結(jié):
- 動(dòng)態(tài)代理非常靈活,可以被任意的接口實(shí)現(xiàn)類對象做代理
- 動(dòng)態(tài)代理可以為被代理對象的所有接口的所有方法做代理俭正,動(dòng)態(tài)代理可以在不改變方法源碼的情況下奸鬓,實(shí)現(xiàn)對方法功能的增強(qiáng)
- 動(dòng)態(tài)代理類的字節(jié)碼(代理對象)在程序運(yùn)行時(shí)由Java反射機(jī)制動(dòng)態(tài)生成,無需程序員手工編寫它的源代碼
- 動(dòng)態(tài)代理不僅簡化了編程工作掸读,而且提高了軟件系統(tǒng)的可擴(kuò)展性全蝶,因?yàn)镴ava反射機(jī)制可以生成任意類型的動(dòng)態(tài)代理類
- 動(dòng)態(tài)代理同時(shí)也提高了開發(fā)效率
- 缺點(diǎn):只針對接口或者接口的實(shí)現(xiàn)類對象做代理對象,普通類是不能做代理對象的
package com.zimo._06_ActiveDemo;
/**
* 業(yè)務(wù)接口
*/
public interface UserService {
String login(String admin, String s);
void deleteAll();
}
package com.zimo._06_ActiveDemo;
/**
* 業(yè)務(wù)實(shí)現(xiàn)類
*/
public class UserServiceImpl implements UserService {
@Override
public String login(String admin, String s) {
if ("admin".equals(admin) && "123456".equals(s))return "success";
return "error";
}
@Override
public void deleteAll() {
System.out.println("del success");
}
}
package com.zimo._06_ActiveDemo;
public class TestDemo {
public static void main(String[] args) {
// 1.創(chuàng)建一個(gè)業(yè)務(wù)對象
//UserService userService = new UserServiceImpl();
// 代理模式
UserService userService = ProxyUtil.getProxy(new UserServiceImpl());
String res = userService.login("admin", "123456"); // 走代理寺枉,不走原來的UserServiceImpl
System.out.println(res);
userService.deleteAll(); // 走代理
}
}
package com.zimo._06_ActiveDemo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 代理對象:幫助我們做一個(gè)被代理的業(yè)務(wù)對象返回
* java.lang.reflect.Proxy:這是Java動(dòng)態(tài)代理機(jī)制的主類
* 它提供了一個(gè)靜態(tài)方法來為一組接口的實(shí)現(xiàn)類動(dòng)態(tài)地生成代理類及其對象(newProxyInstance)
* 參數(shù)一:類加載器:負(fù)責(zé)加載到時(shí)候做好的業(yè)務(wù)代理對象
* 參數(shù)二:被代理業(yè)務(wù)對象的全部實(shí)現(xiàn)的接口,以便代理對象可以知道哪些方法做代理
* 參數(shù)三:代理正真的執(zhí)行方法,也就是代理的處理邏輯
*/
public class ProxyUtil {
/**
* 做一個(gè)被代理的業(yè)務(wù)對象返回
* @param userService
* @return
*/
public static UserService getProxy(UserServiceImpl userService){
return (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), new InvocationHandler() {
@Override
// 類加載器抑淫,類實(shí)現(xiàn)的接口,具體實(shí)現(xiàn)方法邏輯
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
// o:業(yè)務(wù)代理對象本身姥闪,一般用不到 method:當(dāng)前正在被代理執(zhí)行的方法 objects:執(zhí)行方法的參數(shù)
// 添加時(shí)間性能分析,不用在每個(gè)方法中使用
long startTime = System.currentTimeMillis();
// 真正觸發(fā)方法執(zhí)行
Object re = method.invoke(o, objects);
long endTime = System.currentTimeMillis();
System.out.println(endTime - startTime);
return re;
}
});
}
}