spring learning code 2

Thu, Apr 16, 2020 7-minute read

This is my learning note about how Spring core features like IoC, AOP works, with Code Examples .

spring IOC annotation

  • 1. @Compoment
  • 2. @Service
  • 3. @Controller
  • 4. @Repository

dependency

  • spring-aop

start component scan

image

annotation

    <context:component-scan base-package="com.learn"></context:component-scan>
    <context:component-scan base-package="com.learn" use-default-filter="false">
        <context:include-filter type="anotation" expreesion="org.springframework.steretype.Controller">
    </context:component-scan>

set properties (annotation)

1.1 @AotuWired: 根据属性类型进行自动装配

1.2 @Qualifier:根据属性名称进行注入

1.3 @Resource: 可以根据类型注入,可以根据名称注入

1.4 @Value: 注入普通类型属性

steps (annotation)

1.1 dao and service annotation

  • @Resource (UserDaoImpl)
  • @Service (UserService)
image

annotation

Field injection is not recommended(不再推荐使用字段注入)但是国内的使用场景有时候比国外复杂很多,实际情况,就一个业务单元,国内的公司几轮需求加上来,注入的服务就会牵扯到十几个,用构造器注入,奇丑无比;用传统的分层结构,光数据库 dao 的注入,都是好几个

1.2 dao and service annotation

  • @Resource(name = “userDaoImpl1”)
  • @AutoWired + @Qualifier(value = “userDaoImpl1”)
image

annotation

完全注解开发

2.1 comfig class

image

annotation

2.2 test

image

annotation

spring AOP

spring AOP

1.0 面向切面 1.1 登录功能

AOP 底层原理:底层使用动态代理

2.0 有接口,使用 JDK 动态代理

interface UserDao {
    public void login();
}
class UserDao implements UserDao{
    public void login() {
        // 登录实现过程
    }
}
  • JDK 动态代理

      1. 创建 UserDao 接口实现类代理对象
  • 2.1 没有接口,使用 CGLIB 动态代理

class User {
    public void add() {
        。。。。
    }
}
class Person extends User{
    public void add() {
        super.add();
    }
}
  • CGLIB 动态代理

      1. 创建当前子类代理对象
  • 2.3 AOP JDK 使用 Proxy 代理对象

  • 2.4 使用 newProxyInstance 方法代理对象

    • 3 个参数
    • ClassLoader 类加载器
    • 类<?>[] interface 增加方法所在的类,这个类实现的接口,支持多个接口
    • InvocationHandler 实现这个接口 InvocationHandler, 创建代理对象,写增加的方法
  • 2.5 使用 JDK 动态代理代码

  • 创建接口, 定义方法
    public interface Userdao {

    int add(int a, int b);

    String update(String id);

}
  • 创建接口实现类, 实现方法
    public class UserDaoImpl implements Userdao{
    @Override
    public int add(int a, int b) {
        System.out.println("add方法之前执行le");
        return a + b;
    }

    @Override
    public String update(String id) {
        System.out.println("update方法之前执行le");
        return id;
    }
}

    public class UserDaoImpl implements Userdao{
    @Override
    public int add(int a, int b) {
        return a + b;
    }

    @Override
    public String update(String id) {
        return id;
    }
}

  • 使用 Proxy 类创建接口代理对象
public class JDKProxy {
    public static void main(String[] args) {

        Class[] interfaces = {UserDao.class};

        Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
           @Override
           public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
               return null;
           }
        });
    }

or

  1. 创建代理对象代理
public class JDKProxy {
    public static void main(String[] args) {

        Class[] interfaces = {UserDao.class};
        ...
    }
}

class UserDaoProxy implements InvocationHandler {
      // 1. 把创建的是谁的代理对象,把谁传递过来
     // 有参数构造传递
     private Object obj;
     public UserDaoProxy(Object obj) {
         this.obj = obj;
     }
     // 增加的逻辑
         // 增加的逻辑
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
         // 方法之前
        System.out.println("方法之前执行.............." + method.getName() + " : 传递的参数" + Arrays.toString(args));
        Object res = method.invoke(obj, args);
        System.out.println("方法之后执行..........." + obj);
        return res;
    }
}   
public class JDKProxy {
    public static void main(String[] args) {

        Class[] interfaces = {UserDao.class};

        UserDaoImpl userDao = new UserDaoImpl();

        UserDao dao = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));

         int result = dao.add(1, 2);
        System.out.println(result);
    }
}

3.0 AOP 操作

  • 3.1 Spring 框架一般基于 AspectJ 实现 AOP 操作

  • 3.2 AOP 相关依赖

  • 3.3 切入点表达式

execution([权限修饰符][返回类型][类全路径]方法名称)

execution([public/private][返回类型/ 忽略][类全路径]方法名称)

ex1: com.learn.dao.BookDao 里面 add 进行增强 execution(*com.learn.dao.BookDao.add(..))

ex2: com.learn.dao.BookDao 里面所有的方法进行增强 execution(com.learn.dao.BookDao.(..))

ex3: 对 com.learn.dao 包里面所有类,类里面所有的方法进行增强 execution(com.learn.dao..*(..))

4.0 AOP AspectJ 注解

  • 4.1 创建类, 在类里面定义方法

被增强类

public class User {
    public void add() {
        System.out.println("add...........");
    }
}

  • 4.2 创建增强类(编写增强逻辑)
    • 在增强类里面,创建方法,让不同方法代表不同通知类型
// 增强类
public class UserProxy {

    // 前置通知
    public void before() {
        System.out.println("before......................");
    }
}

  • 4.3 进行通知的配置
    • 在 spring 配置文件中,开启注解扫描
    • 使用注解创建 User 和 UserProxy 对象
image

Spring aop

image

Spring aop

image

Spring aop

  • 4.4 在增强类上面添加注解 @Aspect
// 增强类
@Component
@Aspect // 生成代理对象
public class UserProxy {

    // 前置通知
    public void before() {
        System.out.println("before......................");
    }
}

  • 4.5 在 spring 配置文件中开启生成代理对象
image

Spring aop

  • 配置不同类型的通知

    • 在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置
// 增强类
@Component
@Aspect // 生成代理对象
public class UserProxy {

    // 前置通知
    // @Before 注解表示作为配置通知
    @Before("execution(*com.learn.aop.User.add(..)")
    public void before() {
        System.out.println("before......................");
    }
}

image

Spring aop

image

Spring aop

image

Spring aop

  • 4.6 公共切入点抽取
image

Spring aop

  • 4.7 有多个增强类多同一个方法进行增强, 设置增强类优先
    • 在增强类上面添加注解 @Order(数字类型值), 小优先级越高
image

Spring aop

image

Spring aop

5.0 AOP AspectJ 配置文件

  • 5.1 两个类,增强类和被增强类, 创建方法

  • 5.2 在 spring 配置文件中创建两个类对象

    <bean id="book" class="com.learn.aopxml.Book"></bean>
    
    <bean id="bookProxy" class="com.learn.aopxml.BookProxy"></bean>
  • 5.3 在 spring 配置文件中配置切入点
image

Spring aop

spring data access: JDBC

JdbcTemplate

1.0 dependency jar

  • mysql-connector-java (Java 连接 MySQL 需要驱动包,否则 JDBC 无法访问数据库)

  • druid (在 JDBC 访问数据库的时候是通过连接来完成的,但是连接的打开及关闭非常耗时,这时就是数据库连接池的作用了,他来管理这个数据库连接,不会用完立即关闭,可以缓存起来,供下次使用,为 JDBC 连接数据库提供锦上添花的作用,Druid 就是一个数据库连接池,用来管理数据库连接池的)

  • spring-jdbc (Spring JDBC 框架负责所有的低层细节,从开始打开连接,准备和执行 SQL 语句,处理异常,处理事务,到最后关闭连接)

  • spring-tx:为 JDBC、Hibernate、JDO、JPA 等提供的一致的声明式和编程式事务管理

  • spring-orm (ORM 的全称是 Object Relational Mapping,即对象关系映射。它的实现思想就是将关系数据库中表的数据映射成为对象,以对象的形式展现,这样开发人员就可以把对数据库的操作转化为对这些对象的操作。因此它的目的是为了方便开发人员以面向对象的思想来实现对数据库的操作)

2.0 在 spring 配置文件配置数据库连接池

3.0 配置 JdbcTemplate 对象, 注入 DataSource

    <!--JdbcTemplate 对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">

        <!--set方法注入dataSource-->
        <property name="dataSource" ref="dataSource"/>
    </bean>

4.0 创建 service 类,创建 dao 类,在 dao 注入 jdbcTemplate 对象

  • 4.1 开启组件扫描

<!--4.1 开启组件扫描-->
    <context:component-scan base-package="com.learn"/>
  • 4.2 Service 类
@Service
public class BookService {

    // 注入dao
    @Autowired
    private BookDao bookDao ;
}
  • 4.3 Dao 类

@Repository
public class BookDaoImpl implements BookDao{

    // 注入jdbcTemplate
    @Autowired
    private JdbcTemplate jdbcTemplate;
}

JdbcTemplate 操作数据库,添加功能

1.0 对应数据库实体类

2.0 编写 service 和 dao

@Repository
public class BookDaoImpl implements BookDao{

    // 注入jdbcTemplate
    @Autowired
    private JdbcTemplate jdbcTemplate;

    // 添加的方法
    @Override
    public void add(Book book) {
        // 1. 创建 sql 语句
        String sql = "insert into t_book values(?, ?, ?)";
        // 2. 调用方法实现
        int update = jdbcTemplate.update(sql, book.getUserId(), book.getUsername(), book.getUstatus());

        System.out.println(update);
    }
       
    // 删除的方法
    @Override
    public void del(String id) {
        // 1. 创建 sql 语句
        String sql = "delete from t_book where user_id=?";
        // 2. 调用方法实现
        int update = jdbcTemplate.update(sql, id);

        System.out.println(update);
    }
           // 更新的方法
    @Override
    public void update(Book book) {
        // 1. 创建 sql 语句
        String sql = "update t_book set username=?, ustatus=? where user_id=?";
        // 2. 调用方法实现
       Object[] args = {book.getUserId(), book.getUsername(), book.getUstatus()};
        int update = jdbcTemplate.update(sql, args);
        System.out.println(update);
    }

}



    @Test
    public void testAdd() {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        BookService bookService = context.getBean("bookService", BookService.class);
        Book book = new Book();
        book.setUserId("2");
        book.setUsername("bb");
        book.setUstatus("b");
        bookService.addBook(book);
    }

JdbcTemplate 操作数据库,查询

查询表有多少条记录

  • SELECT COUNT(*) FROM t_book

查询返回某个值

  • 1. 查询表有多少条记录, 返回某个值
  • 2. 使用 JdbcTemplate 查询表有多少条记录, 返回某个值
    • queryForObject(String sql, Class requireType)
    • 第一个参数 sql 语句
    • 第二个参数, 返回类性 Class(Integer.class, String.class)
  • 3. daoImpl
    @Override
    public int selectCount() {
        String sql = "select count(*) from t_book";
        Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
        return count;
    }

查询返回对象

  • 1. 场景: 查询图书详情
  • 2. 使用 JdbcTemplate 查询返回对象
    • queryForObject(String sql, RowMappper rowMapper, Object… args)
    • 第一个参数 sql(select * from t_book where user_id=?)语句
    • 第二个参数: RowMapper, 是接口, 返回不同类型数据,使用这个接口里面实现类完成数据封装 new BeanPropertyRowMapper(Book.class)
    • 第三个参数: sql 语句值(问号里面的值 id)
  • 3. daoImpl
   public Book findBookInfo(String id) {
        String sql = "select * from t_book where user_id=?";
        Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class), id);
        return book;
    }

查询返回集合

  • 1. 场景: 查询图书列表分页
  • 2. 使用 JdbcTemplate 查询返回集合
    • query(String sql, RowMappper rowMapper, Object… args)
    • 第一个参数 sql 语句
    • 第二个参数: RowMapper, 是接口, 返回不同类型数据,使用这个接口里面实现类完成数据封装 new BeanPropertyRowMapper(Book.class)
    • 第三个参数: 可以省略
  • 3. daoImpl
    @Override
    public List<Book> findAll() {
        String sql = "select * from t_book";
        List<Book> bookList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Book>(Book.class));
        return bookList;
    }

批量增加操作

  • 1. 场景: 批量操作,比如操作表里面多条记录
  • 2. 使用 JdbcTemplate 查询返回集合
    • batchUpdate(String sql, List<Object[]> batchArgs)
    • 第一个参数 sql 语句
    • 第二个参数: List 集合
  • 3. daoImpl
  @Override
    public void batchAddBook(List<Object[]> batchArgs) {
        String sql = "insert into t_book values(?, ?, ?)";
        int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
        System.out.println(ints);
         System.out.println(Arrays.toString(ints));

    }
  • 4. test
    public void test3() {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        BookService bookService = context.getBean("bookService", BookService.class);

        List<Object[]> batchArgs = new ArrayList<>();
        Object[] o1 = {"6", "hava", "w"};
        Object[] o2 = {"7", "gwe", "we"};
        Object[] o3 = {"8", "cge", "h"};
        batchArgs.add(o1);
        batchArgs.add(o2);
        batchArgs.add(o3);
        bookService.batchAdd(batchArgs);

批量修改操作

  • 1. 场景: 批量操作,比如操作表里面多条记录
  • 2. 使用 JdbcTemplate 查询返回集合
    • batchUpdate(String sql, List<Object[]> batchArgs)
    • 第一个参数 sql 语句
    • 第二个参数: List 集合
  • 3. daoImpl
    @Override
    public void batchUpdateBook(List<Object[]> batchArgs) {
        String sql = "update t_book set user_name=?, ustatus=? where user_id=?";
         int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
        System.out.println(Arrays.toString(ints));

    }
  • 4. test
    public void test3() {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        BookService bookService = context.getBean("bookService", BookService.class);

        List<Object[]> batchArgs = new ArrayList<>();
        // Object[] o1 = {"6", "hava", "w"};
        // Object[] o2 = {"7", "gwe", "we"};
        // Object[] o3 = {"8", "cge", "h"};
        // update t_book set user_name=?, ustatus=? where user_id=? id放最后
        Object[] o1 = { "hava001", "w","6",};
        Object[] o2 = { "hava002", "w","7",};
        Object[] o3 = { "hava003", "w","8",};
        batchArgs.add(o1);
        batchArgs.add(o2);
        batchArgs.add(o3);
        bookService.batchAdd(batchArgs);

批量删除操作

  • 1. 场景: 批量操作,比如操作表里面多条记录
  • 2. 使用 JdbcTemplate 查询返回集合
    • batchUpdate(String sql, List<Object[]> batchArgs)
    • 第一个参数 sql 语句
    • 第二个参数: List 集合
  • 3. daoImpl
    public void batchDeleteBook(List<Object[]> batchArgs) {
        String sql = "delete from t_book  where user_id=?";
        int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
        System.out.println(Arrays.toString(ints));
    }
  • 4. test
    public void test3() {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        BookService bookService = context.getBean("bookService", BookService.class);

        List<Object[]> batchArgs = new ArrayList<>();
        Object[] o1 = { "6"};
        Object[] o2 = { "7"};
        batchArgs.add(o1);
        batchArgs.add(o2);
        bookService.batchDelate(batchArgs);

Ok, It’s time for spring1

Ok, It’s time for spring2

Ok, It’s time for spring mvc