0
点赞
收藏
分享

微信扫一扫

sharding‐jdbc之分库分表实战

香小蕉 04-11 14:00 阅读 3

文章目录

Java反射

Spring框架的IoC基于java反射机制实现,反射是指在运行状态中,对任意类都能知道其所有属性和方法;对任何对象都能调用其所有方法和属性。即程序在运行时能够获取自身信息。
剖析一个类则需获取到该类的class对象,使用到java.lang.classjava.lang.relectAPI,Class对象是反射的根源。

回顾

  1. 首先创建类和测试类
package com.jobs.reflect;

public class Car {
    private String name;
    private String color;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    public Car(String name, String color) {
        this.name = name;
        this.color = color;
    }
    public Car() {
    }
    private void drive(){
        System.out.println("drive");
    }
}
  1. 获取Class对象的多种方法
public class CarTest {
    public carTest1() throws Exception {
        //1 类名.class
        Class aClass1 = Car.class;
        //2 对象.getClass()
        Class aClass2 = new Car().getClass();
        //3 Class.forName("全路径")
        Class aClass3 = Class.forName("com.jobs.reflect.Car");
    }
}
  1. 获取构造方法
public void carTest02() throws Exception{
    //获取所有构造
    //getConstructors()获取public
    //getDeclaredConstructors()获取所有(public、private)
    Class aclass = Car.class;
    Constructor[] constructors = aclass.getConstructors();
    for (Constructor c :
            constructors) {
        System.out.println(c.getName() + " " + c.getParameterCount());
    }
    //指定有参构造创建对象
    //public
    Constructor c1 = aclass.getConstructor(String.class, String.class);
    Car car1 = (Car) c1.newInstance("小米","blue");
    //private
    Constructor c2 = aclass.getDeclaredConstructor(String.class, String.class);
    //必须先允许访问才可更改
    c2.setAccessible(true);
    Car car2 = (Car) c2.newInstance("保时捷","red");
}
  1. 获取属性及向属性赋值
@Test
public void carTest03() throws Exception {
    Class aclass = Car.class;
    Car car = (Car) aclass.getDeclaredConstructor().newInstance();
    //获取所有属性
    //getFields() ---- public
    //getDeclaredFields() ---- 所有
    Field[] fields = aclass.getFields();
    Field[] fieldss = aclass.getDeclaredFields();
    for (Field field :
            fieldss) {
        if (field.getName().equals("name")) {
        	//必须先允许访问才可更改
            field.setAccessible(true);
            field.set(car, "xiaomi");
        }
        if (field.getName().equals("color")) {
            field.setAccessible(true);
            field.set(car, "blue");
        }
        System.out.println(car);
    }
}
  1. 获取方法
public void carTest04() throws Exception {
    Car car = new Car("xiaomi", "blue");
    Class aclass = car.getClass();
    //getMethods() ---- pulic
    //getDeclaredMethods() --- all
    Method[] methods = aclass.getMethods();
    for (Method m :
            methods) {
        if (m.getName().equals("toString")) {
            String invoke = (String) m.invoke(car);
            System.out.println(invoke);
        }
    }
    Method[] methodss = aclass.getDeclaredMethods();
    for (Method m :
            methodss) {
        if (m.getName().equals("drive")) {
            //先许可
            m.setAccessible(true);
            m.invoke(car);
        }
    }
}

AOP

代理模式

  1. 属于结构型模式的设计模式,作用为通过一个代理类,使得在调用目标方法时,不再直接对目标方法进行调用,而是通过代理类进行间接调用。让不属于目标方法核心逻辑的内容从中剥离,达成解耦。
  2. 调用目标方法时先调用代理对象的方法,减少对目标方法的调用和打扰,同时让附加功能能够集中在一起,便于统一维护。
    在这里插入图片描述
    在这里插入图片描述
  1. 静态代理
    创建代理类,在代理类中创建目标对象,非核心逻辑代码外调用目标方法;
    虽然实现了解耦,但代码已经固定,因此不具备灵活性;
public class CalculatorStaticProxy implements Calculator{
	//传入目标对象
	private Calculator calculator;
	public CalculatorStaticProxy(Calculator calculator){
		this.calculator = calculator;
	}
	@Override
	public int add(int a, int b){
		System.out.println("[日志]");
		//调用目标方法
		int result = calculator.add(a, b);
		System.out.println("[日志]");
		return result;
}
  1. 动态代理
    将非核心逻辑功能集中到代理类中,将来有任何此功能需求,都能通过该代理类实现。
    在这里插入图片描述
代理类
public class ProxyFactory {
    //目标对象
    private Object target;
    public ProxyFactory(Object target){
        this.target = target;
    }

    //返回代理对象
    public Object getProxy(){
        /*
        * Proxy.newProxyInstance()有三个参数
        * 1 ClassLoader:加载动态生成代理类的加载器
        * 2 Class[] interfaces:目录对象实现的所有接口的class类型数组
        * 3 InvocationHandler:设置代理对象实现目标对象方法的过程
        * */
        //1 ClassLoader
        ClassLoader classLoader = target.getClass().getClassLoader();
        //2 Class[] interfaces
        Class<?>[] interfaces = target.getClass().getInterfaces();
        //3 InvocationHandler
        InvocationHandler invocationHandler = new InvocationHandler(){
            //1 proxy:代理对象
            //2 method:需要重写目标对象的方法
            //3 args:method方法所需参数
            @Override
            public Object invoke(Object proxy,
                                 Method method,
                                 Object[] args) throws Throwable {
                //方法调用前
                System.out.println("[动态代理日志] "+method.getName()+", 参数" + Arrays.toString(args));
                //调用目标方法
                Object result = method.invoke(target, args);
                //方法调用后
                System.out.println("[动态代理日志] "+method.getName()+", 结果" + result);
                return result;
            }
        };
        return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
    }
}
测试
public class CalculatorTest {
    public static void main(String[] args) {
        ProxyFactory proxyFactory = new ProxyFactory(new CalculatorImpl());
        Calculator proxy = (Calculator) proxyFactory.getProxy();
        proxy.add(1, 2);
    }
}
输出结果
[动态代理日志] add, 参数[1, 2]
[动态代理日志] add, 结果3

AOP概念及术语

概述

AOP(aspect oriented programming)是一种设计思想,面向切面编程,以预编译和运行期动态代理方式实现。在不修改源代码的情况下,给程序动态统一添加额外功能的一种技术。
利用AOP对业务逻辑各部分进行隔离,从而降低耦合,提高程序可重用性,提高开发效率。

术语

  1. 横切关注点
    分散在各模块中解决同一问题,可抽取出来的同一类非核心业务;
    此概念不是语法层面,而是根据附加功能逻辑层面需要;
  2. 通知(增强)
    每一个横切关注点上要做的事情都需要写一个方法来实现,这样的方法就叫通知方法;
  1. 切面
    封装通知方法的类
    在这里插入图片描述
  2. 目标
    被代理的目标对象
  3. 代理
    代理对象
  4. 连接点
    逻辑概念,方法中每个横切位置看作连接点,即Spring允许使用通知的地方
  5. 切入点
    定位连接点的方式,Spring的AOP技术可以通过切入点定位到特定的连接点,即要增强的地方
    eg. 连接点—数据库中的记录;切入点—查询记录的SQL语句

作用

  • 简化代码:抽取固定位置重复代码,让目标方法专注核心功能;
  • 代码增强:特定功能封装进切面类中,在有需要的地方套用,被套用了切面逻辑的方法就被切面增强;

基于注解的AOP

  1. 动态代理分为JDK方式和cglib方式;
  2. 当目标类有接口时使用JDK和cglib方式,没有接口时只能使用cglib方式;
  3. JDK动态代理生成代理类会在com.sun.proxy包下,类名为$proxy1,和目标类实现相同接口;
  4. cglib动态代理生成代理类会在目标相同包下,继承目标类;
    在这里插入图片描述
    在这里插入图片描述
  5. AspectJ:AOP思想的一种实现,本质是静态代理,其将代理逻辑”织入“目标类编译得到的字节码文件,所以最终效果是动态的。Spring只是借用AspectJ的注解。

步骤

  1. 引入AOP依赖
  2. 创建目标资源:接口;实现类;
  3. 创建切面类:切入点;通知类型;

依赖

<!--spring aop-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>6.0.2</version>
</dependency>
<!--spring aspects-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>6.0.2</version>
</dependency>

配置文件

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--组件扫描-->
    <context:component-scan base-package="com.jobs.spring6.aop.annotation_aop"></context:component-scan>

    <!--aspectj自动代理,并为目标对象生成代理-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</bean>

切入点表达式语法

在这里插入图片描述

切面类

设置切面类即可在目标对象上套用切面功能

@Aspect//切面类
@Component//IoC容器
public class LogAspect {

    //设置切入点和通知类型

    //切入点表达式:
    //execution(访问修饰符 增强方法返回类型 增强方法所在类的全路径.方法名称(参数列表)

    //通知类型:
    //前置@Befor(value="切入点表达式")
    @Before(value = "execution(public int com.jobs.spring6.aop.annotation_aop.CalculatorImpl.*(..))")
    public void beforeMethod(){
        System.out.println("before!");
    }

    //返回@AfterReturning
    //returning可以传递至方法内部,要求同名
    @AfterReturning(value = "execution(public int com.jobs.spring6.aop.annotation_aop.CalculatorImpl.*(..))",
            returning = "result")
    public void afterReturningMethod(Object result){
        System.out.println("afterreturning! result: " + result);
    }

    //异常@AfterThrowing
    //throwing可以传递错误信息至方法内部,要求同名
    @AfterThrowing(value = "execution(public int com.jobs.spring6.aop.annotation_aop.CalculatorImpl.*(..))",
            throwing = "exception")
    public void afterThrowingMethod(Throwable exception){
        System.out.println("afterthrowing! exception: " + exception);
    }

    //后置@After
    @After(value = "execution(public int com.jobs.spring6.aop.annotation_aop.CalculatorImpl.*(..))")
    public void afterMethod( ){
        System.out.println("after!");
    }

    //环绕@Around
    @Around(value = "execution(public int com.jobs.spring6.aop.annotation_aop.CalculatorImpl.*(..))")
    public Object afterReturningMethod(ProceedingJoinPoint joinPoint){
        Object result = null;
        try {
            System.out.println("around_before");
            //调用目标方法
            result = joinPoint.proceed();
            System.out.println("around_afterreturn");
        }catch (Throwable throwable){
            throwable.printStackTrace();
            System.out.println("around_afterthrow");
        }finally {
            System.out.println("around_after");
        }
        return result;
    }
}

在这里插入图片描述

重用切入点表达式

  1. 声明
//重用切入点表达式
@Pointcut(value = "execution(* com.jobs.spring6.aop.annotation_aop.CalculatorImpl.*(..))")
public void pointCut() { }
  1. 使用
//在同一个切面中,直接使用缩写
@After(value = "pointCut()")
//在不同切面中,添加缩写全路径
@After(value = "com.jobs.spring6.aop.annotation_aop.LogAspect.pointCut()")

切面的优先级

  1. 外层的切面 > 内层的切面
  2. 利用@Order注解可以控制优先级:

基于XML的AOP

beanaop.xml
<!--配置aop通知类型-->
<aop:config>
    <!--配置切面类-->
    <aop:aspect ref="logAspect">
        <!--配置切入点-->
        <aop:pointcut id="pointcut" expression="execution(*
        com.jobs.spring6.aop.xml_aop.CalculatorImpl.*(..))"/>
        <!--配置通知-->
        <!--before-->
        <aop:before method="beforeMethod" pointcut-ref="pointcut"></aop:before>
        <!--after-->
        <aop:after method="afterMethod" pointcut-ref="pointcut"></aop:after>
        <!--afterreturning-->
        <aop:after-returning method="afterReturningMethod"
                             returning="result"
                             pointcut-ref="pointcut"></aop:after-returning>
        <!--afterthrowing-->
        <aop:after-throwing method="afterThrowingMethod"
                             throwing="exception"
                             pointcut-ref="pointcut"></aop:after-throwing>
        <!--around-->
        <aop:around method="aroundMethod" pointcut-ref="pointcut"></aop:around>
    </aop:aspect>
</aop:config>

单元测试JUnit

减少固定任务

引入依赖

<!--spring整合junit依赖-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>6.0.2</version>
</dependency>

JUnit5

@SpringJUnitConfig(locations = "classpath:bean.xml")
/*      or
@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:bean.xml")
*/
public class SpringJUnitTest {
    //injection
    @Autowired
    private User user;

    //Test
    @Test
    public void userTest(){
        System.out.println(user);
        user.run();
    }
}
举报

相关推荐

0 条评论