GitHub 学习路径(含笔记与代码)

1. 基础

Java 反射机制

Java 动态代理

2. spring IOC(DI)

2.1 ioc 容器

  • 创建

    • pom.xml 引入 jar 包

      1. <dependency>
      2. <groupId>org.springframework</groupId>
      3. <artifactId>spring-context</artifactId>
      4. <version>5.0.2.RELEASE</version>
      5. </dependency>
    • 使用 bean.xml 实现

      1. <beans xmlns="http://www.springframework.org/schema/beans"
      2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      3. xmlns:context="http://www.springframework.org/schema/context"
      4. xsi:schemaLocation="http://www.springframework.org/schema/beans
      5. https://www.springframework.org/schema/beans/spring-beans.xsd
      6. http://www.springframework.org/schema/context
      7. http://www.springframework.org/schema/context/spring-context-4.2.xsd">
      8. <context:component-scan base-package="com.cyt"></context:component-scan>
      9. <bean> </bean>
      10. <aop config> </aop>
    • 使用 annotation 实现

      1. @Configuration // 说明当前是配置类,作用等同于 2.1 ioc 容器 读取注解类
      2. @ComponentScan("com.cyt") // 指定 spring 在创建容器时要扫描的包
      3. @Import({JdbcConfig.class,TransactionConfig.class}) // 用于在主配置类中导入其他子配置类,实现效果和 @ComponentScan({"com.cyt","config"}) 一样
      4. @PropertySource("classpath:jdbcConfig.properties") //用于指定 properties 文件的位置
      5. @EnableTransactionManagement// 开启对事务管理的支持
      6. public class SpringConfiguration {
      7. @Bean(name = "")
      8. @Scope("prototype")
      9. public Object createBean(){
      10. return new Object();
      11. }
  • 获取

    • 读取 bean.xml
      • ApplicationContext ac = new ClassPathXmlApplicationContext(“bean.xml”);
      • @ContextConfiguration(locations = “classpath:bean.xml”)
    • 读取注解类 SpringConfiguration.class
      • ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
      • @ContextConfiguration(classes** **= SpringConfiguration.class)

        2.2 bean 对象

  • 创建

    • xml 实现
      • 使用默认构造函数创建:如果没有无参的构造函数,则无法创建对象
  1. - 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入 spring 容器)

class=”com.cyt.service.impl.AccountServiceImpl”>
  - 使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入 spring 容器)
factory-method=”getAccountService”>
  • annotation 实现
    • Component(value=”bean_id”):默认value是当前类名,其首字母改小写;
    • Controller:一般用于表现层, Service:一般用于业务层, Repository:一般用于持久层;
    • 补充:这三个注解与 component 实现功能一致,只不过是 spring 框架对应三层使用的一个标志区分;
      • 获取
  • xml
    • IAccountService as = ac.getBean(“accountService3”, AccountServiceImpl3.class);
  • annotation

    2.3 bean 的参数配置

  • xml 实现

    • bean 标签的 scope 属性: singleton| prototype,request,session,global-session

    request: 作用于 web 应用的请求范围;
    session: 作用于 web 应用的会话范围;
    global-session: 作用于集群环境的会话范围(全局会话范围),当不是集群环境时,它就是 session;

    • bean 对象的生命周期【spring 框架会依据 scope 属性对单例/多例对象的初始化自动地做不同处理】
      • 单例对象【与容器的生命周期相同】:容器创建时对象出生,容器在对象就在,容器销毁时对象销亡;
      • 多例对象:使用对象时由 spring 框架创建,只要在使用对象就一直活着,若对象长时间不用且无别的对象引用时,由 java 的垃圾回收器回收;
    • 示例
scope=”singleton init-method=”init” destroy-method=”destroy”>
  • annotation 实现

    • 作用范围:默认使用单例模式-singleton

             [@Scope(value="prototype"](#) or "singleton") Class Account{ }
      
    • 声明周期

      • 初始化

@PostConstruct
public void init() { System.out.println(“初始化方法执行啦”); }

  - 销毁

@PreDestroy
public void destroy() { System.out.println(“销毁方法执行啦”); }

2.4 依赖注入

2.4.1 bean 类数据

  • xml 实现
    • 使用 构造函数 注入(使用时必须传入参数,不常用):
<bean id = "accountService" class = "com.cyt.service.impl.AccountServiceImpl">   
     <constructor-arg name="name" value="test"></constructor-arg>   
     <constructor-arg name="age" value="18"></constructor-arg>   
     <constructor-arg name="birthday" ref="now"></constructor-arg> 
</bean>
<bean id="now" class="java.util.Date"></bean>
  • set 方法注入:

    <bean id = "accountService2" class = "com.cyt.service.impl.AccountServiceImpl2">
    <property name="name" value="cyt"></property>
    <property name="age" value="25"></property>
    <property name="birthday" ref="now"></property>
    </bean>
    
  • 注入方式3:

    • annotation 实现
  • Autowired:自动按照类型注入,若存在多个类型匹配,叠用 Qualifer 依据 id 确定 bean 对象;
  • Resource:直接按照 bean id 注入,可独立使用;

    2.4.2 其他数据

  • xml 实现

    • 基本类型 和 String
      • />/>
    • 复杂类型 / 集合类型
      • />/>
      • />/>
      • 111 />/>
      • 111 />/>
    • 总结
      • 用于给 List 结构集合注入的标签: list、array、set;
      • 用于给 Map 结构集合注入的标签: map、properties;

        2.4.3 补充-自动装配

  • xml 实现: default-autowire - 支持 byName、byType、constructor、no 四种选择;

    • 注:前提是需要在 person 类中体现与 car 类的依赖关系; ```java //1. 全局自动配置 <?xml version=”1.0” encoding=”UTF-8”?>

//2. 局部自动配置(每一个单独设置autowire) <?xml version=”1.0” encoding=”UTF-8”?>

<!-- 在xml中只定义bean,无需配置依赖关系 -->
<bean id="person" class="com.bravo.xml.Person" autowire="byName"></bean>
<bean id="car" class="com.bravo.xml.Car"></bean>

</bean


- **annotation 实现**
```java
@Component
public class Person {
    @Autowired
    private Car car;
}

3. spring AOP

3.1 理论

  • 通知类型

    • 前置通知:在切入点方法执行之前执行;
    • 后置通知:在切入点方法正常运行后执行;
    • 异常通知:在切入点方法运行产生异常后执行;
    • 最终通知:无论切入点方法是否正常运行都会在后面执行;
    • 环绕通知:
      • spring 框架提供的 ProceedingJoinPoint 接口,该接口可以作为环绕通知的方法参数,执行其方法 proceed() 相当于明确调用切入点方法;
      • spring 的环绕通知就是提供了可以处理不同通知消息顺序的一个接口;

        3.2 使用

  • pom.xml 引入 jar 包

    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.7</version>
    </dependency>
    
  • xml

    <beans xmlns="http://www.springframework.org/schema/beans"       
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       
      xmlns:aop="http://www.springframework.org/schema/aop"       
      xsi:schemaLocation="http://www.springframework.org/schema/beans       
      https://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/aop
      http://www.springframework.org/schema/aop/spring-aop.xsd>
    <!--配置Logger类-->    
    <bean id="logger" class="com.cyt.utils.Logger"></bean>
    <!--配置AOP-->   
    <aop:config>    
      <!--切入点表达式,此处是所有切面都可用-->    
      <aop:pointcut id="pt1" expression="execution(* com.cyt.service.impl.*.*(..))"/>        
      <!--配置切面, ref 说明是对哪个 bean 进行方法加强-->  
      <aop:aspect id="logAdvice" ref="logger">
          <!--配置通知的类型,并且建立通知方法和切入点方法的关联-->
          <aop:before method="beforePrintLog" pointcut-ref="pt1"></aop:before>
          <aop:after-returningmethod="afterReturningPrintLog"pointcut-ref="pt1"></aop:after-returing>
          <aop:after-throwingmethod="afterThrowingPrintLog"pointcut-ref="pt1"></aop:after-throwing>
          <aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>
          <aop:around method="aroundPrintLog" pointcut-ref="pt1"></aop:around>     
      </aop:aspect> 
    </aop:config>
    
  • annotation(用于需要加强的类上)

    • 类注解 :
      • @Component()
      • @Aspect(“logAdvice”)
      • @EnableAspectJAutoProxy
    • 方法注解
      • @Pointcut(“execution(“”) public void pt1(){}
      • @Before(“pt1()”) 、@AfterReturning(“pt1()”)、@AfterThrowing(“pt1()”)、@After(“pt1()”)、@Around(“pt1()”)
    • 案例:参照 5.3.2 AOP 包装;
  • 注意:执行时,最终通知和后置通知执行顺序有变,在实际开发中应慎重,建议采用环绕通知,采用环绕通知后就无需显示调用其他通知,而是在环绕函数中调用;
  • 补充

    • 切入点表达式
      • 内容:访问修饰符 返回值 包名.包名.包名…类名.方法名(参数列表)
      • 标准表达式: eg. public void com.cyt.service.impl.AccountServiceImpl21_aop.saveAccount()
      • 简化表达式
        -  访问修饰符可省略: void com.cyt.service.impl.AccountServiceImpl21_aop.saveAccount()
        -  返回值可使用通配符,表示任意返回值
           - * com.cyt.service.impl.AccountServiceImpl21_aop.saveAccount()
        - 包名可以使用通配符,表示任意包,但是有几级包,就需要写几个*.
           - eg.   * *.*.*.*.AccountServiceImpl21_aop.saveAccount()
        - 包名可以使用..表示当前包及其子包:
           - eg.   * *..AccountServiceImpl21_aop.saveAccount()
        - 类名和方法名都可以使用 * 来实现通配:
           - eg. * *..*.*()     【针对无参方法】
        - 可以直接写数据类型:
           -  基本类型直接写名称:* *..*.*(int)
           - 引用类型写包名.类名的方式:全通配写法:* *..*.*(..)
        
        • 实际开发中切入点表达式的通常写法:
          • 切到业务层实现类下的所有方法 com.cyt.service.impl..*(..)
    • 此标签写在 aop:aspect 标签内部就只能被当前切面使用,其还可以写在 aop:aspect 外面,此时就变成了所有切面可用;

      4. spring 与 Junit 集成

      4.1 Junit 特性

  • junit 本身集成有一个 main 方法,该方法会自动判断当前测试类中哪些方法有 @Test 注解,然后让有 Test 注解的方法执行;

  • 独立于 spring 框架,在执行测试方法时,junit 根本不知道是否使用 spring 框架,因此并不会自动读取配置文件 或 类创建的 spring 核心容器;
  • 测试方法执行时无 ioc 容器,即便写了 Autowired 注解也无法实现注入;

    4.2 集成配置

    注意:**当使用 spring 5.x 版本的时候,要求 junit 的 jar 必须是 4.12 及以上;**

  • 导入 spring 整合 junit 的 jar 包(坐标)

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>
  • 使用 junit 提供的一个注解把原有的 main 方法替换,替换成 spring 提供的 @Runwith
    • @RunWith(SpringJUnit4ClassRunner.class)
  • 告知 spring 的运行期,spring 和 ioc 创建是基于 xml 还是注解类,并说明位置 @ContextConfiguration,详见2.1 ioc 容器获取

    5. spring 事务管理

    5.1 配置

    • 第一步:引入 jar 包

      <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.0.2.RELEASE</version>
      </dependency>
      
    • 第二步: bean.xml 引入

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:tx="http://www.springframework.org/schema/tx"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
      https://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/tx
      http://www.springframework.org/schema/tx/spring-tx.xsd">
      
    • 第三步:bean.xml 配置事务管理器

      <bean id="transactionManager"  
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource" ref="dataSource"></property>
      </bean>
      <!--配置数据源-->
      <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
      <property name="url" value="jdbc:mysql://localhost:3306/eesy"></property>
      <property name="username" value="root"></property>
      <property name="password" value="1234"></property>
      </bean>
      

5.2 使用

  • xml

    • 第一步:在 bean.xml 中开启 spring 对事务的支持:

      <tx:annotation-driven transaction-manager="transactionManager">
      </tx:annotation-driven>
      
    • 第二步:在 bean.xml 配置事务的通知

      <tx:advice id="txAdvice" transaction-manager="transactionManager">
      <tx:attributes>
      <tx:method name="*" propagation="REQUIRED" read-only="false"/>
      <tx:method name="find" propagation="SUPPORTS" read-only="true"></tx:method>
      </tx:attributes>
      </tx:advice>
      
    • 第三步:在 bean.xml 配置 AOP

      <aop:config>
      <aop:pointcut id="pt1" expression="execution(* com.cyt.service.impl.*.*(..))"/>
      <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor>
      </aop:config>
      
  • annotation

    • 用于类

@EnableTransactionManagement// 开启对事务管理的支持
@Transactional(propagation = Propagation.REQUIRED, readOnly = false)

  - 用于类或方法上

@Transactional(propagation = Propagation.SUPPORTS, readOnly = true

5.3 自定义一个简单的事务管理类

5.3.1 BeanProxy(xml版)

  • bean.xml

factory-bean=”beanFactory” factory-method=”getAccountService1”/>




public class BeanFactory {
    private IAccountService1 accountService1;
    private TransactionManager tsManager;
    public void setAccountService1(IAccountService1 accountService1) {
        this.accountService1 = accountService1;
    }
    public void setTsManager(TransactionManager tsManager) {
        this.tsManager = tsManager;
    }
    public IAccountService1 getAccountService1() {
        // 织入:把增强应用到目标对象来创建新的代理对象的过程
        IAccountService1 asProxy = (IAccountService1) Proxy.newProxyInstance(
            accountService1.getClass().getClassLoader(),
            accountService1.getClass().getInterfaces(),
            //切面(Aspect)是切入点和通知(引介)的结合
            new InvocationHandler() {
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    Object returnValue = null;
                    try {
                        //1. 开启事务
                        tsManager.beginConnection();//前置通知
                        //2. 执行操作
                        returnValue = method.invoke(accountService1, args); // 整个invoke方法在执行就是环绕通知,且环绕通知中有明确的切入点方法调用
                        //3. 提交事务
                        tsManager.commit();//后置通知
                        //4. 返回结果
                        return returnValue;
                        } catch (Exception e) {
                        //5. 回滚操作
                        tsManager.rollback(); //异常通知
                        throw new RuntimeException(e);
                    } finally {
                        //6. 释放资源
                        tsManager.release(); //最终通知
                    }
                }
            });
        return asProxy;
    }
}

5.3.2 AOP 包装(注解版)

  • 分析:
    • proxy.invoke() 方法 和 AOP 实现中 环绕通知 的实现逻辑是一致的;
    • 为实现通用性:
      • 切入点表达式:说明要做加强处理的包、类或方法;
      • 在环绕通知内提供了一个 ProceedingJoinPoint 类来做具体执行;
        @Component("txManager")
        @Aspect
        @EnableAspectJAutoProxy
        public class TransactionManager {
        @Autowired
        private ConnectionUtils connectionUtils;
        @Pointcut("execution(*com.cyt.service.impl.AccountServiceImpl11.transfer(..))")
        private void pointCut(){}
        @Before("pointCut()")
        public void beginConnection(){
        try {
         connectionUtils.getThreadConnection().setAutoCommit(false);
        } catch (Exception e) {
         e.printStackTrace();
        }
        }
        @AfterReturning("pointCut()")
        public void commit(){
        try {
         connectionUtils.getThreadConnection().commit();
        } catch (Exception e) {
         e.printStackTrace();
        }
        }
        @AfterThrowing("pointCut()")
        public void rollback(){
        try {
         connectionUtils.getThreadConnection().rollback();
        } catch (Exception e) {
         e.printStackTrace();
        }
        }
        @After("pointCut()")
        public void release(){
        try {
         connectionUtils.getThreadConnection().close();
         connectionUtils.removeConnection();
        } catch (Exception e) {
         e.printStackTrace();
        }
        }
        @Around("pointCut()")
        public void aroundTansfer(ProceedingJoinPoint pjp){
        Object[] args = pjp.getArgs();
        try {
         //1. 开启事务
         beginConnection();
         //2. 执行操作
         pjp.proceed(args);  
         //3. 提交事务
         commit();
         //4. 返回结果
        } catch (Throwable t) {
         //5. 回滚操作
         rollback(); 
         throw new RuntimeException(t);
        } finally {
         //6. 释放资源
         release();
        }
        }
        }
        

6. spring 连接数据库

6.1 Dbutil

  • pom.xml 引入 jar 包

       <dependency>
           <groupId>commons-dbutils</groupId>
           <artifactId>commons-dbutils</artifactId>
           <version>1.4</version>
       </dependency>
    
       <dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
           <version>5.1.6</version>
           <scope>runtime</scope>
       </dependency>
    
       <dependency>
           <groupId>c3p0</groupId>
           <artifactId>c3p0</artifactId>
           <version>0.9.1.2</version>
       </dependency>
    
  • 配置

    • 方式一:xml

      <bean id="accountDao" class="com.cyt.dao.impl.AccountDaoImpl">
      <property name="runner" ref="runner"></property>
      <property name="connectionUtils" ref="connectionUtils"></property>//保证单一连接
      </bean>
      <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
      <constructor-arg name="ds" ref="dataSource"></constructor-arg>
      </bean>
      <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
      <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
      <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/eesy"></property>
      <property name="user" value="root"></property>
      <property name="password" value="1234"></property>
      </bean>
      
    • 方式二:annotation ```java @Configuration @PropertySource(“classpath:jdbcConfig.properties”) public class JdbcConfig { @Value(“${jdbc.driver}”) private String driver; @Value(“${jdbc.url}”) private String url; @Value(“${jdbc.username}”) private String user; @Value(“${jdbc.password}”) private String password;

    @Bean(name = “runner”) @Scope(“prototype”) public QueryRunner createQueryRunner(DataSource dataSource){ return new QueryRunner(dataSource); } @Bean(name = “dataSource”) public DataSource createDataSource(){ try {

       ComboPooledDataSource ds = new ComboPooledDataSource();
       ds.setDriverClass(driver);
       ds.setJdbcUrl(url);
       ds.setUser(user);
       ds.setPassword(password);
       return ds;
    

    } catch (Exception e) {

       throw new RuntimeException(e);
    

    } } } ```

  • CURD 操作

    • select

      List<Account1> account1s = runner.query(
              connectionUtils.getThreadConnection(),
              "select * from account where name = ?", 
              new BeanListHandler<Account1>(Account1.class), accountName);
      Account account = runner.query(
              connectionUtils.getThreadConnection(),
              "select * from account", 
              new BeanListHandler<Account1>(Account1.class));
      
    • insert

      runner.update(connectionUtils.getThreadConnection(),
            "insert into account(name,money) values(?,?)", 
            account1.getName(),account1.getMoney());
      
    • update

      runner.update(connectionUtils.getThreadConnection(),
            "update account set name=?,money=? where id=?", 
            account1.getName(),account1.getMoney(),account1.getId());
      
    • delete

      runner.update(connectionUtils.getThreadConnection(),
            "delete from account where id=?", 
            accountId);
      

6.2 JdbcTemplate

  • pom.xml 引入 jar 包

       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-jdbc</artifactId>
           <version>5.0.2.RELEASE</version>
       </dependency>
       <dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
           <version>5.1.6</version>
           <scope>runtime</scope>
       </dependency>
    
  • 配置

    • 方式一:xml

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
      https://www.springframework.org/schema/beans/spring-beans.xsd">
      <!-- 读取db.properties配置文件到Spring容器中
      <context:property-placeholder location="classpath:db.properties" /> -->
      <!--配置 AccountDao12-->
      <bean id="accountDao12" class="com.cyt.dao.impl.AccountDaoImpl12">
      <!--           <property name="jt" ref="jdbcTemplate"></property>-->
             <property name="dataSource" ref="dataSource"></property>
      </bean>
      <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
             <property name="dataSource" ref="dataSource"></property>
      </bean>
      <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
              <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
              <property name="url" value="jdbc:mysql://localhost:3306/eesy"></property>
              <property name="username" value="root"></property>
              <property name="password" value="1234"></property>
      </bean>
      </beans>
      
    • 方式二:annotation ```java @Configuration @PropertySource(“classpath:jdbcConfig.properties”) public class JdbcConfig { @Value(“${jdbc.driver}”) private String driver; @Value(“${jdbc.url}”) private String url; @Value(“${jdbc.username}”) private String user; @Value(“${jdbc.password}”) private String password;

    @Bean(name=”jdbcTemplate”) public JdbcTemplate createJdbcTemplate(DataSource dataSource){ return new JdbcTemplate(dataSource); } @Bean(name=”dataSource_DM”) public DataSource createDataSource_DM(){ DriverManagerDataSource ds = new DriverManagerDataSource(); ds.setDriverClass(driver); ds.setJdbcUrl(url); ds.setUser(user); ds.setPassword(password); return ds; } } ```

    • 方式三: 继承 JdbcDaoSupport,此时不需要配置 和 注入 jdbcTempalte 的 Bean;
  • CURD 操作 ```java public class AccountDaoImpl12 extends JdbcDaoSupport implements IAccountDao1 {

    public Account1 findAccountById(Integer accountId) { List account1s = getJdbcTemplate().query(

       "select * from account where id = ?", 
       new BeanPropertyRowMapper<Account1>(Account1.class), accountId);
    

    return account1s.isEmpty()?null:account1s.get(0); } public void updateAccount(Account1 account1) { getJdbcTemplate().update(

       "update account set name=?,money=? where id=?", 
       account1.getName(),account1.getMoney(),account1.getId());
    

    } public void saveAccount(Account1 account1) { getJdbcTemplate().update(

       "insert into account(name,money) values(?,?)", 
        account1.getName(),account1.getMoney());
    

    } public void deleteAccount(Integer accountId) { getJdbcTemplate().update(

                 "delete from account where id=?", 
                 accountId);
    

    } }

```

6.3 Mybatis

7. Spring 的加载机制

参考

  1. 黑马教程 spring