一.设计模式
-
反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
简单理解:
反射:
通过class文件对象(Class对象、字节码文件对象),去创建类对象、使用其构造方法、成员函数和成员方法,
然后通过反射得到的对象Method,Fielde等对象,反过来执行类中的方法和属性。
1.1设计模式的分类
-
创建型:创建对象。有:工厂模式、单例模式
-
结构型:对象间的关系。有:装饰模式
-
行为型:对象能够做什么。模板模式。
-
增强型:对象除了做什么,还能额外做什么,有:代理模式
1.2常见的设计模式
1.2.1 单例模式: 在内存中保证创建一个对象。
-
应用场景:在项目中,如果对象的状态没有改变,使用单列模式,反之使用多列模式
比如:事务操作中,必须保证事务对象是同一个。
比如:在请求操作中,请求对象必须是多个。
/** * 单列模式:在内存中,保证使用的是同一个对象 * 满足如下规范 * 1.提供私有的无参构造方法 * 2.对外提供一个获取对象的方法 */ //饿汉式写法: 立即创建对象 public class A { //1.私有的构造方法 private A(){ } //2.提供一个方法:对外获取对象 private static A a = new A(); public static A getBean(){ return a; } } /** * 单列模式:在内存中,保证使用的是同一个对象 * 满足如下规范 * 1.提供私有的无参构造方法 * 2.对外提供一个获取对象的方法 */ //懒汉式写法: 立即创建对象 public class B { //1.私有的构造方法 private B(){ } //2.提供一个方法:对外获取对象 private static B b = null; public static B getBean(){ if(b==null){ b= new B(); } return b; } }
1.2.2 工厂模式:加载配置文件,获取对象装到“容器中”。
-
应用场景:通过工厂构建对象,解决程序中的耦合问题
-
/** * 简单工厂: 代码存在耦合问题依然存在。 */ public class Factory1 { //1.提供一个方法:创建对象 public static Object getBean(Class z) throws Exception { return z.newInstance(); } //2.泛型:表示任意类型,解决类型强转问题 public static <T> T getBean2(Class z) throws Exception{ T t = (T) z.newInstance(); return t; } } /** * 解决:耦合问题 * 思路:配置文件+ 反射= Factoy2 * 配置文件: xml (properties, yml) * 在配置文件加载完毕,把所有对象存到“容器中” * “容器”: 一般指的计算机的内存空间,直接的说通过集合或者数组保存对象,集合或者数组 就是容器 */ public class Factory3 { //1.加载配置文件 private static Document document; //2.创建容器对象 private static Map<String,Object> map = new HashMap<String,Object>(); static { try { //1.1.创建解析器对象 SAXReader saxReader = new SAXReader(); //1.2 获取配置文件的字节输入流 InputStream in = Factory3.class.getClassLoader().getResourceAsStream("beans.xml"); //1.3 获取文档对象 document = saxReader.read(in); //1.4读取所有标签 获取id ,class List<Element> list = document.selectNodes("//bean"); //1.5,把id作为map的key,把class反射后的对象作为value for (Element element : list) { String key = element.attributeValue("id");// dog ,cat Object value =Class.forName( element.attributeValue("class")).newInstance(); map.put(key,value);// dog--->Dog } } catch (Exception e) { e.printStackTrace(); } } //2.创建对象:从容器中获取 public static <T> T getBean2(String idValue) throws Exception{ return (T)map.get(idValue); } }
1.3 代理模式
-
代理: 在开发中,给接口或者类进行代理,目的为了增强接口或者类中的方法。
-
代理分类
-
基于jdk代理(sun提供): 基于接口代理,给接口生成一个代理类
-
基于第三方代理(cglib): 基于类进行代理,给当前类生成一个代理类
-
package cn.tedu.proxy_model; public interface Lenovo { void sellComputer(double money); } package cn.tedu.proxy_model; public class TagSeller implements Lenovo { @Override public void sellComputer(double money) { System.out.println("卖电脑:"+money ); } } public class Demo4 { /** * jdk代理:基于接口代理,给接口生成一个代理类(代理类实现了该接口) * 比如: * 早前: 联想公司卖电脑 * 代理商的模式: * 联想公司----》某个A省份代理商 * 联想公司----》某个B省份代理商 */ @Test public void testX(){ //1.生成代理类 //参数一:类加载器(应用类加载器) ClassLoader loader = UserMapper.class.getClassLoader(); //参数二:接口(提供接口) Class[] interfaces = {UserMapper.class}; //参数三:增强器对象 InvocationHandler handler = new InvocationHandler() { // proxy : 代理对象, Method : 执行的方法, args: 执行方法的参数 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("执行sql前----检查sql语法是否正确"); Object obj = method.invoke(new UserMapper() { @Override public void addUser() { System.out.println("真正的添加--执行sql"); } }, args);// proxy.addUser(); System.out.println("执行sql后----处理结果"); return null; } }; UserMapper proxy = (UserMapper) Proxy.newProxyInstance(loader,interfaces,handler); proxy.addUser(); } @Test public void testX2(){ Lenovo tag = new TagSeller(); Class[] interfaces = {Lenovo.class}; Lenovo proxy =(Lenovo) Proxy.newProxyInstance(tag.getClass().getClassLoader(), interfaces, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("来这买电脑,送优惠券--前置增强"); Double mm = (Double) args[0]; method.invoke(tag,mm.intValue()+200);//执行卖电脑的方法 System.out.println("买完电脑,车送你回家---后置增强"); return null; } }); proxy.sellComputer(800.00); } }
-
-
应用场景
-
spring框架中: 默认使用jdk代理,选择cglib代理
-
springsecurity,shiro : 安全校验框架,基于cglib代理。
-
mybatis框架: 基于mapper接口开发,选择jdk代理
-
-
1.3根据设计模式分析--spring框架底层原理
-
spring底层创建bean对象时
工厂模式,单列模式,代理模式等等
-
spring进行全注解开发时
-
1.使用@Configuration标识当前类是一个配置类,替代配置文件的
-
2.使用@ComponentScan(basePackages = "cn.tedu.bean_factory.pojo"),开启包扫描
@Component: 创建一个普通的bean @Controller : 创建web层的bean @Service: 创建业务层对象 @Repository: 创建dao层对象(@Mapper)
/** * 配置类: 替代配置文件 */ @ComponentScan(basePackages = "cn.tedu.bean_factory.pojo") @Configuration public class SpringConfig { }
-
1.4 springBoot自动装配原理
1.4.1 如何开启包扫描
结论:
通过Registrar----》 AutoConfigurationPackages 扫描包(扫描启动类的包以及子包)自己创建的类以及sprigboot提供的必须bean
通过AutoConfigurationImportSelector----》ConfigurationClassBeanDefinitionReader-->springboot的jar/METE-INF/spring.properties
步骤一: @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration//指定当前是一个配置类 public @interface SpringBootConfiguration { } 步骤二: @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage// 自动扫描包 @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; } 步骤三: @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import({Registrar.class})//扫描包 public @interface AutoConfigurationPackage { } static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { Registrar() { } public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());//1.开启包扫描 2.注入写的bean,提供必要bean }