Spring

IOC

获取实例

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
// 1. 通过 id 获取实例
Student student = (Student) applicationContext.getBean("student");
// 2. 通过运行时类获取实例 (缺点:xml 中一种数据类型只能有一个实例)
//Student student = (Student) applicationContext.getBean(Student.class);
System.out.println(student);

Bean 配置

  1. 无参构造
<bean id="student" class="com.southwind.entity.Student"
    scope="prototype" parent="student" autowire="byType" depends-on="a2">
    <property name="id" value="1"/>
    <property name="name" value="张三"/>
    <property name="age" value="12"/>
    <property name="address" ref="address"/>
</bean>
  • scope: 默认为 singleton,单例模式,prototype 为工厂模式
  • panent 参数:不同对象只要属性相同就能继承
  • autowire: byName 根据 id=(address) 寻找,根据 class=(Student) 寻找
  • depend-on: 规定 bean 创建顺序
  1. 有参构造
<bean id="student3" class="com.southwind.entity.Student">
    <constructor-arg name="id" value="3"/>
    <constructor-arg name="name" value="李四"/>
    <!--可以用 index 代替 name,但是也要按顺序写-->
    <constructor-arg name="age" value="14"/>
    <!--<constructor-arg index="2" value="14"/>-->
    <constructor-arg name="address" ref="address"/>
    <constructor-arg name="addresses">
        <list>
            <ref bean="address"/>
            <ref bean="address2"/>
        </list>
    </constructor-arg>
</bean>

::: tip 提示 spring 通过反射调用无参构造创建对象,bean 必须有无参构造 ::: ClassPathXmlApplicationContext 类实现了 ApplicationContext 接口,有 getBean 方法 下面是一个 ClassPathXmlApplicationContext 的简单实现

public class ClassPathXmlApplicationContext implements ApplicationContext {

    private Map<String, Object> ioc = new HashMap<>();

    public ClassPathXmlApplicationContext(String path) {
        try {
            // xml 文件解析
            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read("./src/main/resources/" + path);
            System.out.println(document);
            Element root = document.getRootElement();
            Iterator<?> iterator = root.elementIterator();
            // 遍历所有节点
            while (iterator.hasNext()) {
                Element element = (Element) iterator.next();
                String id = element.attributeValue("id");
                String className = element.attributeValue("class");
                // 通过反射创建对象
                Class<?> clazz = Class.forName(className);
                // 获取无参构造函数
                Constructor<?> constructor = clazz.getConstructor();
                Object object = constructor.newInstance();
                Iterator<Element> beanIterator = element.elementIterator();
                while (beanIterator.hasNext()) {
                    Element property = beanIterator.next();
                    String name = property.attributeValue("name");
                    String value = property.attributeValue("value");
                    String ref = property.attributeValue("ref");
                    // 获取 set 方法
                    // 1. 拼接方法名
                    String methodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
                    // 2. 获取形参类型
                    Field field = clazz.getDeclaredField(name);
                    // 3. 获取带参数的方法
                    Method method = clazz.getDeclaredMethod(methodName, field.getType());
                    // 4. 将实参类型 String 转换为所需的
                    String fieldName = field.getType().getName();
                    if (fieldName == "long") {
                        method.invoke(object, Long.parseLong(value));
                    } else if (fieldName == "int") {
                        method.invoke(object, Integer.parseInt(value));
                    } else {
                        method.invoke(object, value);
                    }
                    if (ref != null) {
                        method.invoke(object, ioc.get(ref));
                        // 这里可能要做个递归
                        // 或者是把 bean 全找到后再根据 ref 互相赋值
                        // 这里简单写
                    }
                }
                ioc.put(id, object);
                System.out.println(object);
            }
            System.out.println("XML 解析完毕");
        } catch (DocumentException | ClassNotFoundException | NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalArgumentException | IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

    }

    @Override
    public Object getBean(String id) {
        return ioc.get(id);
    }
}
  1. 静态工厂
  • factory
public class StaticCarFactory {
    private static Map<Long, Car> carMap;
    static {
        carMap = new HashMap<>();
        carMap.put(1L, new Car(1L, "宝马"));
        carMap.put(2L, new Car(2L, "奔驰"));
    }
    public static Car getCar(long id) {
        return carMap.get(id);
    }
}
  • spring.xml
<!--配置静态工厂-->
<bean id="car" class="com.southwind.factory.StaticCarFactory"               factory-method="getCar">
    <constructor-arg value="2"/>
</bean>
  1. 实例工厂
  • factory
public class InstanceCarFactory {
    private Map<Long, Car> carMap;
    public InstanceCarFactory() {
        carMap = new HashMap<>();
        carMap.put(1L, new Car(1L, "宝马"));
        carMap.put(2L, new Car(2L, "奔驰"));
    }
    public Car getCar(long id) {
        return carMap.get(id);
    }
}
  • xml
<!--配置实例工厂-->
<bean id="carFactory" class="com.southwind.factory.InstanceCarFactory"/>
<bean id="car2" factory-bean="carFactory" factory-method="getCar">
    <constructor-arg value="2"/>
</bean>

AOP

手动反射实现

  • handler
public class CalInvocationHandler implements InvocationHandler {
    // 接受委托对象
    private Object object = null;

    // 返回代理对象
    public Object bind(Object object) {
        this.object = object;
        // 获取运行时类
        Class<?> clazz = object.getClass();
        // 获取类加载器
        ClassLoader classLoader = clazz.getClassLoader();
        // 获取类的所有接口
        Class<?>[] interfaces = clazz.getInterfaces();
        //创建能实现委托对象所有功能的代理对象
        return Proxy.newProxyInstance(classLoader, interfaces, this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(method.getName() + "的参数是" + Arrays.toString(args));
        Object result = method.invoke(this.object, args);
        System.out.println(method.getName() + "的结果是" + result);

        return result;
    }
}
  • Test
public class Test {
    public static void main(String[] args) {
        Cal cal = new CalImpl();
        CalInvocationHandler calInvocationHandler = new CalInvocationHandler();
        cal = (Cal) calInvocationHandler.bind(cal);
        cal.add(1, 2);
    }
}

@Aspect 实现

  • loggerAspect
@Aspect  // 让普通对象成为切面对象
@Component  // 交给 ioc 管理 bean  同时委托对象也要被 ioc 管理
public class loggerAspect {

    // 方法名用*代替  参数用..代替
    //@Before("execution(public int com.southwind.utils.impl.CalImpl.add(int, int))")
    @Before("execution(int com.southwind.utils.impl.CalImpl.*(..))")
    public void before(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        String args = Arrays.toString(joinPoint.getArgs());
        System.out.println(methodName + "的参数是" + args);
    }

    @After("execution(int com.southwind.utils.impl.CalImpl.*(..))")
    public void after(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println(methodName + "执行完毕");
    }

    @AfterReturning(
            value = "execution(int com.southwind.utils.impl.CalImpl.*(..))",
            returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println(methodName + "的结果是" + result);
    }

    @AfterThrowing(
            value = "execution(int com.southwind.utils.impl.CalImpl.*(..))",
            throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Exception e) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println(methodName + "抛出异常" + e);
    }
}
  • spring.xml
<!--自动扫描 base-package 下的对象,将添加了 @component 注解的对象加入 ioc 容器-->
<context:component-scan base-package="com.southwind"/>

<!--自动扫描,为添加了 @aspect 注解的对象自动生成代理对象-->
<aop:aspectj-autoproxy/>
  • Test2
// 加载配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
// 自动生成的代理对象被自动加入 ioc,
// @component("id") 如果不加参数 bean 的 id 为委托对象首字母小写
Cal proxy = (Cal) applicationContext.getBean("calImpl");
proxy.add(1, 2);

spring-mvc

Mybatis

  • pom.xml
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.6</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.23</version>
</dependency>
  • config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--    配置 mybits 运行环境-->
    <environments default="development">
        <environment id="development">
<!--            JDBC 事务管理-->
            <transactionManager type="JDBC"></transactionManager>
<!--            POOLED 配置数据库连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/library?useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value=""/>
            </dataSource>
        </environment>
    </environments>
    <!--注册 xml 文件-->
    <mappers>
        <mapper resource="com/southwind/mapper/AccountMapper.xml"></mapper>
        <mapper resource="com/southwind/mapper/StudentMapper.xml"></mapper>
        <mapper resource="com/southwind/mapper/ClassesMapper.xml"></mapper>
    </mappers>
</configuration>