2.详细讲解
- 配置类
- @Configuration: 代表这是一个配置类,和我们之前看的beans.xml一样
- @Bean:注册一个bean,就相当于我们之前写的bean标签,这个方法的名字相当于bean标签的id属性。方法的返回值就相当于bean中的class属性
- @ComponentScan(“Com.Jsxs.pojo”) 扫描包
- @Import(JsxsConfig2.class) 导入包
- 实体类
- @Component: 这个注解的意思,就是说明这个类被Spring接管了,注册到了容器中;表名一个类作为组件类,并告知Spring要为这个类创建bean
- 测试类
- 如果我们完全使用了配置类方式去做,我们就只能通过 ACAC 进行获取
3.小结
这种纯java的配置方式,在SpringBoot中随处可见!
(十一)、注解(总结)
- @SuppressWarnings(“all”) ====》镇压警告(方法和类上都可以)
- @Override ====》重写的注解 (方法上)
- @Target ====》注解的作用域 (方法 字段 类)
- @Target(value = {ElementType.METHOD}) //设置的只能在方法上使用
- @Retention 注解运行状态
- @Retention(value = RetentionPolicy.RUNTIME) //跑动的时候有效
- @Documented ====》 是否生成JavaDoc
- @Inherited ====》 是否进行子类继承父类
- @interface ====》自定义的注解
(十二)、代理模式
1.为什么要使用代理模式?
因为这就是SpringAop的底层;
- 静态代理
- 动态代理
2.静态代理
- 抽象角色: 一般会使用接口和抽象类来解决(租房子这个事情)
- 真实角色:被代理的角色(房东或则客户)
- 代理角色:代理真是对象,代理真实角色后,我们一般会做一些附属操作。(中介)
- 客户:访问代理角色的人
静态代理: 代理对象和被代理对象都要实现接口,然后代理对象可以扩展功能。
(1).客户租房子案列
房东想出租一套房子,但是只想把钥匙给它,其他的什么事情都不想做。于是乎房东想到了中介可以帮助我们完成这些事情,然后就去找中介进行办理了手续。于是乎: 中介也了解房东的心思,不想管那么多的事情,于是就让房东交出房子的钥匙(rent)和身份证信息(host),然后就让房东走了。然后此时此刻有一个客户(cilent)找到了中介(proxy),在中介的介绍下,客户选择了房东名字叫做Host的这个房子,于是找代理进行办理,
接口
package com.Jsxs.demo1; //出租房子这件事 public interface rent { void rent(); }
房东1
package com.Jsxs.demo1; public class Host implements rent{ @Override public void rent() { System.out.println("房东: 我要出租房子"); } }
中介
package com.Jsxs.demo1; // 房东先拉过来 打一架;然后再继承房东的房子 public class proxy implements rent{ /* 中介下面有很多的房东,然后中介只要调用出租房子这个接口,然后调取某个房东的房子去出租 */ private Host host; //房东1 public proxy() { } public proxy(Host host) { this.host = host; } @Override public void rent() { host.rent(); this.fare(); this.regular(); } // 中介扩展 public void fare(){ System.out.println("中介收取费用"); } public void regular(){ System.out.println("中介签合同"); } }
客户
package com.Jsxs.demo1; // 客人 : 租房子 public class Client { public static void main(String[] args) { // 第一套方案 : 无中介直接找厂家 Host host = new Host(); host.rent(); // 第二套方案 : 不找房东 找中介 proxy proxy = new proxy(host); proxy.rent(); } }
(2).代理模式的好处
- 可以使真实角色的操作更加存粹! 不用去关注一些公共的事务
- 公共也就是交给代理角色,实现业务的分工
- 公共业务发生扩展的时候,方便集中管理!
(3).代理模式的缺点
- 一个真实角色就会产生一个代理角色;代码量会进行翻倍·开发效率会变低。
为什么说 一个真实角色就会产生一个代理对象? 是因为我们在中介(proxy)类中,只能设置一个房东,如果设置两个房东,那么我们的(proxy)构造函数要同时写两个房东的信息,然而客户只会选择一套房子进行操作,所以不能一个代理做两个房东的生意.
(4).代理模式真实案列
我们此次的实验是: 我们通过客户(Client)类,实现对实际业务的需求。我们这次要求在每次运行的时候都要进行添加日志的操作! 不要轻易改变公司的原有结构代码,因为接口不只是你在用,运用代理模式这样可以分工操作,所以我们不能对原有结构进行修改。
UserServic接口
package com.Jsxs.demo2; public interface UserService { void add(); void delete(); void update(); void query(); }
UserServic接口实现类
package com.Jsxs.demo2; public class UserServiceImpl implements UserService{ @Override public void add() { System.out.println("增加了一个用户"); } @Override public void delete() { System.out.println("删除了一个用户"); } @Override public void update() { System.out.println("修改了一个用户"); } @Override public void query() { System.out.println("查询了一个用户"); } }
客户类(实现)
package com.Jsxs.demo2; public class Cilent { public static void main(String[] args) { UserService userService = new UserServiceImpl(); UserProxy userProxy = new UserProxy(userService); userProxy.add(); } }
代理类
package com.Jsxs.demo2; public class UserProxy implements UserService{ private UserService userService; public UserProxy(UserService userService) { this.userService = userService; } public UserProxy() { } @Override public void add() { log("add"); userService.add(); } @Override public void delete() { log("delete"); userService.delete(); } @Override public void update() { log("update"); userService.update(); } @Override public void query() { log("query"); userService.query(); } public void log(String msg){ System.out.println("【Debug】"+"使用了"+msg+"方法"); } }
3.动态代理(代理的是接口)
- 动态代理和静态代理角色一样
- 动态代理类是动态生成的,不是我们自己手动写的。
- 动态代理分为两类: 基于接口的动态代理,基于类的动态代理
- 基于接口 : JDK动态代理【我们在这里使用】
- 基于类 : cglib
- Java字节码 : javasist
1.环境搭配
(1).需要了解两个类
Proxy : 代理
InvocationHandler : 调用处理程序
InvocationHandler是由代理实例的调用处理程序实现的接口 。 每个代理实例都有一个关联的调用处理程序。 当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的invoke方法
(2).动态代理的好处
- 可以使真实角色的操作更加存粹! 不用去关注一些公共的事务
- 公共也就是交给代理角色,实现业务的分工
- 公共业务发生扩展的时候,方便集中管理!
- 一个 动态 代理类的是一个接口,一般对应的就是一类业务
- 一个动态代理类 可以代替多个类,只要实现了同一个接口
(3).非完全动态代理
我是房东: 我想向外面租房子。想找个中介帮忙进行处理这件事情。
接口
package com.Jsxs.demo3; //出租房子这件事 public interface rent { void rent(); }
房东实现接口
package com.Jsxs.demo3; public class Host implements rent { @Override public void rent() { System.out.println("房东1: 我要向外出租房子"); } }
自动生成代理类
(1).我们在这里继承: 调用处理程序这个接口(InvocationHandler) (2).创建真实对象(被代理对象) (3).生成得到代理类: 类加载器;被代理对象的接口;调用处理程序; Proxy.newProxyInstance(this.getClass().getClassLoader(),rent1.getClass().getInterfaces(),this); (4).重写(InvocationHandler)接口的方法 (5).在重写的方法里面写: 目的是进行代理执行 Object invoke = method.invoke(rent1, args);
package com.Jsxs.demo3; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /* 我们用这个类,自动生成代理类 */ public class proxyInvocationHandler implements InvocationHandler { private rent rent1; public void setRent1(rent rent1) { this.rent1 = rent1; } // 生成得到代理类 public Object getPoxy(){ // 类加载器 ==》接口 ===》 InvocationHandler return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent1.getClass().getInterfaces(),this); } // 处理代理实列,并返回结果 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { seeHouse(); // 动态代理的实质就是使用反射机制 Object invoke = method.invoke(rent1, args); write(); return null; } public void seeHouse(){ System.out.println("看房"); } public void write(){ System.out.println("签合同"); } }
客户类(实现类)
(1).创建真实对象(被代理对象) (2).创建代理类 (3).向代理类里面写入被代理对象 (4).获取代理类; 强制类型转换成(接口的类型,不是接口的实现类)
package com.Jsxs.demo3; public class Client { public static void main(String[] args) { //真实对象 Host host = new Host(); //代理角色 : 现在没有 proxyInvocationHandler pih = new proxyInvocationHandler(); //通过调用程序处理角色来处理我们要调用的接口对象 pih.setRent1(host); rent poxy = (rent) pih.getPoxy(); //这里的proxy就是动态生成的,我们没有写 poxy.rent(); } }
(4).完全动态代理
只需要做出一些改变,就是引入被代理对象的时候,我们不进行指定的类型,而直接写出Object的类型就可以。
万能
package com.Jsxs.demo4; import com.Jsxs.demo3.rent; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /* 我们用这个类,自动生成代理类 */ public class proxyInvocationHandler implements InvocationHandler { private Object target; public void setTarget(Object target) { this.target = target; } // 生成得到代理类 public Object getPoxy(){ // 类加载器 ==》接口 ===》 InvocationHandler return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this); } // 处理代理实列,并返回结果 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 动态代理的实质就是使用反射机制 Object invoke = method.invoke(target, args); return null; } }
客户
package com.Jsxs.demo4; import com.Jsxs.demo2.UserService; import com.Jsxs.demo2.UserServiceImpl; public class Client { public static void main(String[] args) { // 真实角色 UserServiceImpl userService = new UserServiceImpl(); // 代理角色,不存在 proxyInvocationHandler handler = new proxyInvocationHandler(); // 要动态处理的对象 handler.setTarget(userService); // 动态生成代理类 UserService poxy = (UserService) handler.getPoxy(); poxy.add(); } }
(5).总结
静态代理和动态代理的区别: 就是我们在中介类(代理类)的时候继承的东西不一样,静态代理类继承的接口是(被代理对象的接口类),动态代理类继承的是调用程序处理类(InvocationHandler)