spring框架

Spring
工厂模式
工厂设计模式BeanFactory + 反射 + 配置文件
在实际开发中我们可以把三层的对象都使用配置文件配置起来,当启动服务器应用加载的时候,让一个类中的
方法通过读取配置文件,把这些对象创建出来并存起来。在接下来的使用的时候,直接拿过来用就好了。
那么,这个读取配置文件,创建和获取三层对象的类就是工厂
/**

  • 产生 bean 对象的工厂
    /
    public class BeanFactory {
    private static final Map<String, Object> map = new HashMap<String, Object>(); //工厂容器
    static {
    try {
    InputStream in =BeanFactory.class.getClassLoader().getResourceAsStream(“bean.properties”);
    Properties prop = new Properties();
    prop.load(in);
    Set keys = prop.keySet();
    for (Object key : keys) {
    //key 代表 properties中的key
    String value = prop.getProperty((String) key);
    Class clazz = Class.forName(value);
    Object object = clazz.newInstance();
    map.put((String)key, object);
    }
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    /
    *
  • 根据 id 值获取对应的bean对象
  • @param id
  • @return
    */
    public static Object getBean(String id) {
    return map.get(id);
    }
    }
    spring 概述和优势
    1.概述
    2.优势
    Spring 是分层的 Java SE/EE 应用 full-stack 轻量级开源框架,以 IoC(Inverse Of Control:
    反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层 Spring
    MVC 和持久层 Spring JDBC 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多
    著名的第三方框架和类库,逐渐成为使用最多的 Java EE 企业应用开源框架。
    方便解耦,简化开发
    通过 Spring 提供的 IoC 容器,可以将对象间的依赖关系交由 Spring 进行控制,避免硬编码所造
    成的过度程序耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可
    以更专注于上层的应用
    AOP 编程的支持
    通过 Spring 的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现的功能可以通过 AOP
    轻松应付。
    声明式事务的支持
    可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理,
    提高开发效率和质量。
    方便程序的测试
    可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可
    做的事情。
    方便集成各种优秀框架
    Spring 可以降低各种框架的使用难度,提供了对各种优秀框架(Struts、Hibernate、Hessian、Quartz
    等)的直接支持
    降低 JavaEE API 的使用难度
    Spring 对 JavaEE API(如 JDBC、JavaMail、远程调用等)进行了薄薄的封装层,使这些 API 的
    使用难度大为降低
    Java 源码是经典学习范例
    Spring 的源代码设计精妙、结构清晰、匠心独用,处处体现着大师对 Java 设计模式灵活运用以
    及对 Java 技术的高深造诣。它的源代码无意是 Java 技术的最佳实践的范例
    IOC-控制反转
    概念和作用
    使用 spring 的 IOC 削减程序耦合
  1. 准备 spring 的开发包
  2. service层和dao层的创建
  3. XML 的配置
    3.1 创建Bean的三种方式
    概念:控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的
    耦合问题,也是轻量级的Spring框架的核心。 控制反转一般分为两种类型,依赖注入(Dependency Injection,简称
    DI)和依赖查找(Dependency Lookup)。依赖注入应用比较广泛。
    作用:削减计算机程序的耦合(解除我们代码中的依赖关系)。
    官网:http://spring.io/
    下载地址:
    http://repo.springsource.org/libs-release-local/org/springframework/spring
    坐标:

    org.springframework
    spring-context
    5.0.2.RELEASE

    默认构造函数(无参构造方法)
    resources/xxxx.xml
<?xml version="1.0" encoding="UTF-8"?>




3.2 bean的作用范围调整
3.2 bean对象的生命周期
3.3 Spring Bean 实现步骤
第一种方式:使用默认构造函数创建。
在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时。
采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数(无参构造方法),则对象无法创建。

第二种方式: 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)



第三种方式:使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
<bean id=“accountService” class=“com.itheima.factory.StaticFactory” factorymethod=“getAccountService”>
bean标签的scope属性:
作用:用于指定bean的作用范围
取值: 常用的就是单例的和多例的
singleton:单例的(默认值)
prototype:多例的
request:作用于web应用的请求范围
session:作用于web应用的会话范围
global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境时,它就是session


单例对象
出生:当容器创建时对象出生
活着:只要容器还在,对象一直活着
死亡:容器销毁,对象消亡
总结:单例对象的生命周期和容器相同
多例对象
出生:当我们使用对象时spring框架为我们创建
活着:对象只要是在使用过程中就一直活着。
死亡:当对象长时间不用,且没有别的对象引用时,由Java的垃圾回收器回收
调用构造器 Bean.constructor,进行实例化;
调用 Setter 方法,设置属性值;
调用 BeanNameAware.setBeanName,设置Bean的ID或者Name;
调用 BeanFactoryAware.setBeanFactory,设置BeanFactory;
调用 ApplicationContextAware.setApplicationContext,置ApplicationContext;
调用BeanPostProcessor的预先初始化方法,如下:
BeanPostProcessor1.postProcessBeforeInitialization
ApplicationContext & BeanFactory
ApplicationContext的三个常用实现类
核心容器的两个接口引发出的问题:
测试
DI-spring的依赖注入
BeanPostProcessor2.postProcessBeforeInitialization
BeanPostProcessor3.postProcessBeforeInitialization
……
调用由 @PostConstruct 注解的方法;
调用 InitializingBean.afterPropertiesSet;
调用 Bean.init-mehod 初始化方法;
调用BeanPostProcessor的后初始化方法,如下:
BeanPostProcessor1.postProcessAfterInitialization
BeanPostProcessor2.postProcessAfterInitialization
BeanPostProcessor3.postProcessAfterInitialization
*ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下。不在的话,
加载不了。(更常用)
*FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(必须有访问权限)
*AnnotationConfigApplicationContext:它是用于读取注解创建容器的
ApplicationContext: 单例对象适用 采用此接口
它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。也就是说,只要一读取完配置文件马上就创建
配置文件中配置的对象。
BeanFactory: 多例对象使用
它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。也就是说,什么时候根据id获取对象了,什么
时候才真正的创建对象。
//1.使用 ApplicationContext 接口,就是在获取 spring 容器
ApplicationContext ac = new ClassPathXmlApplicationContext(“xxxx.xml”);
//2.根据 bean 的 id 获取对象
IAccountService aService = (IAccountService) ac.getBean(“accountService”);
System.out.println(aService);
IAccountDao aDao = (IAccountDao) ac.getBean(“accountDao”);
System.out.println(aDao);
构造函数注入
set方法注入(常用)
能注入的数据:有三类
基本类型和String
其他bean类型(在配置文件中或者注解配置过的bean)
复杂类型/集合类型
注入的方式:有三种
第一种:使用构造函数提供(了解)
第二种:使用set方法提供(常用)
第三种:使用注解提供
使用的标签:constructor-arg
标签出现的位置:bean标签的内部
标签中的属性
name(常用):用于指定给构造函数中指定名称的参数赋值
type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值。索引的位置是从0开始
=以上三个用于指定给构造函数中哪个参数赋值===================
value:用于提供基本类型和String类型的数据
ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
优势:
在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功。
弊端:
改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。





涉及的标签:property
出现的位置:bean标签的内部
标签的属性
name:用于指定注入时所调用的set方法名称
value:用于提供基本类型和String类型的数据
ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
优势:
创建对象时没有明确的限制,可以直接使用默认构造函数
弊端:
如果有某个成员必须有值,则获取对象是有可能set方法没有执行。
集合类型的注入





用于给List结构集合注入的标签:list array set
用于个Map结构集合注入的标签: map props
结构相同,标签可以互换



AAA
BBB
CCC




AAA
BBB
CCC




AAA
BBB
CCC




ccc
ddd






spring 中 IOC 常用的注解
xml 的配置(扫描注解包的位置)
用于创建对象的
用于注入数据的
BBB



<?xml version="1.0" encoding="UTF-8"?>

<context:component-scan base-package=“com.itheima”></context:component-scan>


<property name="" value="" | ref="">

他们的作用就和在XML配置文件中编写一个标签实现的功能是一样的

  • Component:
    作用:用于把当前类对象存入spring容器中
    属性:
    value:用于指定bean的id。当我们不写时,它的默认值是当前类名,且首字母改小写。
  • Controller:一般用在表现层
  • Service:一般用在业务层
  • Repository:一般用在持久层
    以上三个注解他们的作用和属性与Component是一模一样。
    他们三个是spring框架为我们提供明确的三层使用的注解,使我们的三层对象更加清晰
    用于改变作用范围的
    用于生命周期
    使用 spring 的 ioc 的实现CRUD
    他们的作用就和在xml配置文件中的bean标签中写一个标签的作用是一样的
  • Autowired:
    作用:自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入
    成功
    如果ioc容器中没有任何bean的类型和要注入的变量类型匹配,则报错。
    如果Ioc容器中有多个类型匹配时:先根据类型匹配, 再根据名称匹配
    出现位置:
    可以是变量上,也可以是方法上
    细节:
    在使用注解注入时,set方法就不是必须的了。
  • Qualifier:
    作用:在按照类中注入的基础之上再按照名称注入。它在给类成员注入时不能单独使用,配合 Autowired
    使 用。但是在给方法参数注入时可以
    属性:
    value:用于指定注入bean的id。
    *** Resource
    作用:直接按照bean的id注入。它可以独立使用
    先根据名称匹配, 再根据类型匹配
    属性:
    name:用于指定bean的id。
    以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。
    另外,集合类型的注入只能通过XML来实现。
  • Value
    作用:用于注入基本类型和String类型的数据
    属性:
    value:用于指定数据的值。它可以使用spring中SpEL(也就是spring的el表达式)
    SpEL的写法:${表达式}
    他们的作用就和在bean标签中使用scope属性实现的功能是一样的
  • Scope
    作用:用于指定bean的作用范围
    属性:
    value:指定范围的取值。常用取值:singleton prototype
    他们的作用就和在bean标签中使用init-method和destroy-methode的作用是一样的
  • PreDestroy
    作用:用于指定销毁方法
  • PostConstruct
    作用:用于指定初始化方法
  1. 导入连接池坐标
    C3P0
    Druid
  2. service的实现

    c3p0
    c3p0
    0.9.1.2


    com.alibaba
    druid
    1.1.10

    public class AccountServiceImpl implements IAccountService{
    private IAccountDao accountDao;
    public void setAccountDao(IAccountDao accountDao) {
    this.accountDao = accountDao;
    }
    @Override
    public List findAllAccount() {
    return accountDao.findAllAccount();
    }
    @Override
    public Account findAccountById(Integer accountId) {
    return accountDao.findAccountById(accountId);
    }
    @Override
    public void saveAccount(Account account) {
    accountDao.saveAccount(account);
    }
    @Override
    public void updateAccount(Account account) {
    accountDao.updateAccount(account);
    }
  3. dao的实现
    @Override
    public void deleteAccount(Integer acccountId) {
    accountDao.deleteAccount(acccountId);
    }
    }
    public class AccountDaoImpl implements IAccountDao {
    private QueryRunner runner;
    public void setRunner(QueryRunner runner) {
    this.runner = runner;
    }
    @Override
    public List findAllAccount() {
    try{
    return runner.query(“select * from account”,new BeanListHandler
    (Account.class));
    }catch (Exception e) {
    throw new RuntimeException(e);
    }
    }
    @Override
    public Account findAccountById(Integer accountId) {
    try{
    return runner.query("select * from account where id = ? ",new BeanHandler
    (Account.class),accountId);
    }catch (Exception e) {
    throw new RuntimeException(e);
    }
    }
    @Override
    public void saveAccount(Account account) {
    try{
    runner.update(“insert into
    account(name,money)values(?,?)”,account.getName(),account.getMoney());
    }catch (Exception e) {
    throw new RuntimeException(e);
    }
    }
    @Override
    public void updateAccount(Account account) {
    try{
    runner.update(“update account set name=?,money=? where
    id=?”,account.getName(),account.getMoney(),account.getId());
    }catch (Exception e) {
  4. 基于xml bean 的 ioc 配置
  5. 测试
    throw new RuntimeException(e);
    }
    }
    @Override
    public void deleteAccount(Integer accountId) {
    try{
    runner.update(“delete from account where id=?”,accountId);
    }catch (Exception e) {
    throw new RuntimeException(e);
    }
    }
    }
<?xml version="1.0" encoding="UTF-8"?>

public class AccountServiceTest { @Test public void testFindAll() { //1.获取容易 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.得到业务层对象 IAccountService as = ac.getBean("accountService",IAccountService.class); //3.执行方法 List accounts = as.findAllAccount(); for(Account account : accounts){ System.out.println(account); } } @Test public void testFindOne() { //1.获取容易 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.得到业务层对象 IAccountService as = ac.getBean("accountService",IAccountService.class); //3.执行方法 Account account = as.findAccountById(1); System.out.println(account); } @Test public void testSave() { Account account = new Account(); account.setName("test"); account.setMoney(12345f); //1.获取容易 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.得到业务层对象 IAccountService as = ac.getBean("accountService",IAccountService.class); //3.执行方法 as.saveAccount(account); } @Test public void testUpdate() { //1.获取容易 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.得到业务层对象 IAccountService as = ac.getBean("accountService",IAccountService.class); //3.执行方法 Account account = as.findAccountById(4); account.setMoney(23456f); as.updateAccount(account); } @Test 6.基于注解的 ioc 配置 spring的零配置开发 @Configuration public void testDelete() { //1.获取容易 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.得到业务层对象 IAccountService as = ac.getBean("accountService",IAccountService.class); //3.执行方法 as.deleteAccount(4); } } @Repository public class AccountDaoImpl implements AccountDao { @Autowired private QueryRunner runner; } @Service public class AccountServiceImpl implements AccountService { @Autowired private IAccountDao accountDao; } @ComponentScan @Bean @Import @PropertySource 配置代码 作用:指定当前类是一个配置类 细节:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写。 作用:用于通过注解指定spring在创建容器时要扫描的包 属性: value:它和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包。 我们使用此注解就等同于在xml中配置了: 作用:用于把当前方法的返回值作为bean对象存入spring的ioc容器中 属性: name:用于指定bean的id。当不写时,默认值是当前方法的名称 细节: 当我们使用注解配置方法时,如果方法有参数,spring框架会去容器中查找有没有可用的bean对象。 查找的方式和Autowired注解的作用是一样的 作用:用于导入其他的配置类 属性: value:用于指定其他配置类的字节码。 当我们使用Import的注解之后,有Import注解的类就父配置类,而导入的都是子配置类 作用:用于指定properties文件的位置 属性: value:指定文件的名称和路径。 关键字:classpath,表示类路径下 @Configuration //指定当前类是一个配置类 @ComponentScan(basePackages="com.itheima") //用于通过注解指定spring在创建容器时要扫描的包 @Import({JdbcConfig.class, CacheConfig.class}) //用于导入其他的配置类 @PropertySource("classpath:jdbc.properties") //用于指定properties文件的位置 public class SpringConfiguration { @Bean(name="runner") //用于把当前方法的返回值作为bean对象存入spring的ioc容器中 public QueryRunner createQueryRunner(DataSource ds){ Spring 整合 Junit 动态代理 概述 return new QueryRunner(ds); } @Bean(name="ds") public DataSource createDataSource(){ ComboPooledDataSource ds = new ComboPooledDataSource(); ... return ds; } } test: ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class); 1、导入spring整合junit的jar(坐标) 2、使用Junit提供的一个注解把原有的main方法替换了,替换成spring提供的 @Runwith 3、告知spring的运行器,spring和ioc创建是基于xml还是注解的,并且说明位置 @ContextConfiguration locations:指定xml文件的位置,加上classpath关键字,表示在类路径下 classes:指定注解类所在地位置 当我们使用spring 5.x版本的时候,要求junit的jar必须是4.12及以上 @RunWith(SpringJUnit4ClassRunner.class) //把原有的main方法替换 @ContextConfiguration(locations="classpath:bean.xml") //指定xml文件的位置 @ContextConfiguration(classes = SpringConfiguration.class) //指定注解类所在地位置 spring - test @RunWith(SpringJUnit4ClassRunner.class) //把原有的main方法替换 @ContextConfiguration(classes = SpringConfiguration.class) //指定注解类所在地位置 public class AccountServiceTest { @Autowired //注入数据 private IAccountService as = null; } 基于接口的动态代理(jdk) * 特点:字节码随用随创建,随用随加载 * 作用:不修改源码的基础上对方法增强 * 分类: 基于接口的动态代理(jdk) 基于子类的动态代理(cglib) * 基于子类的动态代理: 涉及的类:Enhancer 提供者:第三方cglib库 如何创建代理对象: 使用Proxy类中的newProxyInstance方法 创建代理对象的要求: *** 被代理类最少实现一个接口,如果没有则不能使用 * newProxyInstance方法的参数: ClassLoader:类加载器 它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法。 Class[]:字节码数组 它是用于让代理对象和被代理对象有相同方法。固定写法。 * InvocationHandler:用于提供增强的代码 它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须 的。 此接口的实现类都是谁用谁写。 注意: *目标对象必须实现接口 *代理对象内部维护了一个目标对象的引用 *代理对象和目标对象都实现相同接口 /** * 通过jdk的代理方式创建了一个生产者的代理对象 */ public class Client { public static void main(String[] args) { final Producer producer = new Producer(); //生产者 IProducer proxyProducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(), producer.getClass().getInterfaces(), new InvocationHandler() { /** * 作用:执行被代理对象的任何接口方法都会经过该方法 * 方法参数的含义 * @param proxy 代理对象的引用 * @param method 当前执行的方法 * @param args 当前执行方法所需的参数 * @return 和被代理对象方法有相同的返回值 * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws 基于子类的动态代理(cglib) Throwable { //提供增强的代码 Object returnValue = null; //1.获取方法执行的参数 Float money = (Float)args[0]; //2.判断当前方法是不是销售 if("saleProduct".equals(method.getName())) { //在此进行对目标对象方法的增强的操作 //producer--真正干活的是目标对象 returnValue = method.invoke(producer, money*0.8f); } return returnValue; } }); proxyProducer.saleProduct(10000f); } } 基于子类的动态代理: * 涉及的类:Enhancer * 提供者:第三方cglib库 * 如何创建代理对象: 使用Enhancer类中的create方法 * 创建代理对象的要求: 被代理类不能是最终类 * create方法的参数: Class:字节码 它是用于指定被代理对象的字节码。 * Callback:用于提供增强的代码 它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。 此接口的实现类都是谁用谁写。 我们一般写的都是该接口的子接口实现类:MethodInterceptor public class Client { public static void main(String[] args) { final Producer producer = new Producer(); Producer cglibProducer = (Producer)Enhancer.create(producer.getClass(), new MethodInterceptor() { /** * 执行北地阿里对象的任何方法都会经过该方法 * @param proxy * @param method * @param args * 以上三个参数和基于接口的动态代理中invoke方法的参数是一样的 * @param methodProxy :当前执行方法的代理对象 * @return * @throws Throwable */ 动态代理事务控制(手写aop编程) @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { //提供增强的代码 Object returnValue = null; //1.获取方法执行的参数 Float money = (Float)args[0]; //2.判断当前方法是不是销售 if("saleProduct".equals(method.getName())) { returnValue = method.invoke(producer, money*0.8f); } return returnValue; } }); cglibProducer.saleProduct(12000f); } } 相关对象的依赖 Spring 中的 AOP AOP概述 AOP的术语 DataSource 不依赖任何对象, 最底层的对象 QueryRunner 不依赖任何对象(进行事务管理), 之前依赖DataSource(不进行事务管理) AccountDao 依赖QueryRunner(执行sql语句), 依赖ConnectionUtils(获取数据库连接) AccountService 依赖AccountDao, 依赖TransactionManager(封装了控制事务的方法) ConnectionUtils 依赖DataSource(维护连接对象), 维护当前线程ThreadLocal TransactionManager 依赖ConnectionUtils(获取当前线程连接,管理事务) AOP:全称是 Aspect Oriented Programming 即:面向切面编程。 简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础 上,对我们的已有方法进行增强 基于 XML 的 AOP 配置 Joinpoint(连接点): 指那些被拦截到的点(方法)。 Pointcut(切入点): 指要对哪些 Joinpoint 进行拦截。 Advice(通知/增强): 指拦截到 Joinpoint 之后所要做的事情。 通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知 Aspect(切面): 是切入点 + 通知 Target(目标对象): 代理的目标对象 Proxy(代理): 一个类被 AOP 织入增强后,就产生一个结果代理类 1、把通知Bean也交给spring来管理 2、使用aop:config标签表明开始AOP的配置 3、使用aop:aspect标签表明配置切面 id属性:是给切面提供一个唯一标识 ref属性:是指定通知类bean的Id。 4、在aop:aspect标签的内部使用对应标签来配置通知的类型 我们现在示例是让printLog方法在切入点方法执行之前之前:所以是前置通知 aop:before:表示配置前置通知 method属性:用于指定Logger类中哪个方法是前置通知 pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强 切入点表达式的写法: 关键字:execution(表达式) 表达式: 访问修饰符 返回值 包名.包名.包名...类名.方法名(参数列表) 标准的表达式写法: public void com.itheima.service.impl.AccountServiceImpl.saveAccount() 访问修饰符可以省略 void com.itheima.service.impl.AccountServiceImpl.saveAccount() 返回值可以使用通配符,表示任意返回值 * com.itheima.service.impl.AccountServiceImpl.saveAccount() 包名可以使用通配符,表示任意包。但是有几级包,就需要写几个*. * *.*.*.*.AccountServiceImpl.saveAccount()) 包名可以使用..表示当前包及其子包 * *..AccountServiceImpl.saveAccount() 类名和方法名都可以使用*来实现通配 * *..*.*() 参数列表: 可以直接写数据类型: 基本类型直接写名称 int 引用类型写包名.类名的方式 java.lang.String 可以使用通配符表示任意类型,但是必须有参数 可以使用..表示有无参数均可,有参数可以是任意类型 全通配写法: * *..*.*(..) Advice(通知/增强) 基于注解的 AOP 配置 实际开发中切入点表达式的通常写法: 切到业务层实现类下的所有方法 * com.itheima.service.impl.*.*(..) <?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?> @Component("logger") @Aspect//表示当前类是一个切面类 public class Logger { @Pointcut("execution(* com.itheima.service.impl.*.*(..))") private void pt1(){} /** * 前置通知 */ // @Before("pt1()") public void beforePrintLog(){ System.out.println("前置通知Logger类中的beforePrintLog方法开始记录日志了。。。"); } /** * 后置通知 */ // @AfterReturning("pt1()") public void afterReturningPrintLog(){ System.out.println("后置通知Logger类中的afterReturningPrintLog方法开始记录日志了。。。"); } /** * 异常通知 */ // @AfterThrowing("pt1()") public void afterThrowingPrintLog(){ System.out.println("异常通知Logger类中的afterThrowingPrintLog方法开始记录日志了。。。"); } /** * 最终通知 */ spring中的JdbcTemplate 概述 // @After("pt1()") public void afterPrintLog(){ System.out.println("最终通知Logger类中的afterPrintLog方法开始记录日志了。。。"); } /** * 环绕通知 * 问题: * 当我们配置了环绕通知之后,切入点方法没有执行,而通知方法执行了。 * 分析: * 通过对比动态代理中的环绕通知代码,发现动态代理的环绕通知有明确的切入点方法调用,而我们的代码 中没有。 * 解决: * Spring框架为我们提供了一个接口:ProceedingJoinPoint。该接口有一个方法proceed(),此方法就 相当于明确调用切入点方法。 * 该接口可以作为环绕通知的方法参数,在程序执行时,spring框架会为我们提供该接口的实现类供我们使 用。 * * spring中的环绕通知: * 它是spring框架为我们提供的一种可以在代码中手动控制增强方法何时执行的方式。 */ @Around("pt1()") public Object aroundPringLog(ceedingJoinPoint pjp){ Object rtValue = null; try{ Object[] args = pjp.getArgs();//得到方法执行所需的参数 System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。前置"); rtValue = pjp.proceed(args);//明确调用业务层方法(切入点方法) System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。后置"); return rtValue; }catch (Throwable t){ System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。异常"); throw new RuntimeException(t); }finally { System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。最终"); } } } 配置数据源 配置数据库的操作模板 配置 C3P0 数据源 JdbcTemplate 的增删改查操作 基本使用 它是 spring 框架中提供的一个对象,是对原始 Jdbc API 对象的简单封装。spring 框架为我们提供了很多 的操作模板类。 需要导入一个 spring-tx-5.0.2.RELEASE.jar(它是和事务相关的) org.springframework spring-tx 5.0.2.RELEASE <?xml version="1.0" encoding="UTF-8"?> public static void main(String[] args) { //1.获取容器 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.获取对象 JdbcTemplate jt = ac.getBean("jdbcTemplate",JdbcTemplate.class); //保存 jt.update("insert into account(name,money)values(?,?)","fff",5000); //修改 在 dao 中使用 JdbcTemplate 在 dao 中定义 JdbcTemplate jt.update("update account set money = money-? where id = ?",300,6); //删除 jt.update("delete from account where id = ?",6); //查询一个 List account = jt.query("select * from account where id = ? ", new AccountRowMapper(), 55); System.out.println(as.isEmpty()?null:account.get(0)); //查询所有 List accounts = jt.query("select * from account where money > ?", new BeanPropertyRowMapper(Account.class), 800); for (Account account : accounts) { System.out.println(account); } //查询返回一行一列:使用聚合函数,在不使用 group by 字句时,都是返回一行一列。最常用的就是分页中 获 取总记录条数 Integer total = jt.queryForObject("select count(*) from account where money > ? ",Integer.class,500); System.out.println(total); /** * 账户的持久层实现类 */ @Repository public class AccountDaoImpl2 implements IAccountDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public Account findAccountById(Integer accountId) { List accounts = jdbcTemplate.query("select * from account where id = ?",new BeanPropertyRowMapper(Account.class),accountId); return accounts.isEmpty()?null:accounts.get(0); } @Override public Account findAccountByName(String accountName) { List accounts = jdbcTemplate.query("select * from account where name = ?",new BeanPropertyRowMapper(Account.class),accountName); if(accounts.isEmpty()){ return null; } if(accounts.size()>1){ throw new RuntimeException("结果集不唯一"); } return accounts.get(0); 测试 让 dao 继承 JdbcDaoSupport } @Override public void updateAccount(Account account) { jdbcTemplate.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId()); } } public static void main(String[] args) { //1.获取容器 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.获取对象 IAccountDao accountDao = ac.getBean("accountDao",IAccountDao.class); Account account = accountDao.findAccountById(1); System.out.println(account); account.setMoney(30000f); accountDao.updateAccount(account); } JdbcDaoSupport 是 spring 框架为我们提供的一个类,该类中定义了一个 JdbcTemplate 对象,我们可以 直接获取使用,但是要想创建该对象,需要为其提供一个数据源:具体源码如下: public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao { @Override public Account findAccountById(Integer accountId) { List accounts = super.getJdbcTemplate().query("select * from account where id = ?",new BeanPropertyRowMapper(Account.class),accountId); return accounts.isEmpty()?null:accounts.get(0); } @Override public Account findAccountByName(String accountName) { List accounts = super.getJdbcTemplate().query("select * from account where name = ?",new BeanPropertyRowMapper(Account.class),accountName); if(accounts.isEmpty()){ return null; } if(accounts.size()>1){ throw new RuntimeException("结果集不唯一"); } return accounts.get(0); } 两版 Dao 的区别 spring中的事务控制 事务控制的 API 1. PlatformTransactionManager 2. TransactionDefinition 3.TransactionStatus 基于 XML 的配置方式 需要的jar包 需要的约束 @Override public void updateAccount(Account account) { super.getJdbcTemplate().update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId()); } } 第一种在 Dao 类中定义 JdbcTemplate 的方式,适用于所有配置方式(xml 和注解都可以) 第二种让 Dao 继承 JdbcDaoSupport 的方式,只能用于基于 XML 的方式,注解用不了 org.springframework spring-jdbc 5.0.2.RELEASE org.springframework spring-tx 5.0.2.RELEASE 配置步骤 代码块 <?xml version="1.0" encoding="UTF-8"?> spring中基于XML的声明式事务控制配置步骤 1、配置事务管理器 2、配置事务的通知 此时我们需要导入事务的约束 tx名称空间和约束,同时也需要aop的 使用tx:advice标签配置事务通知 属性: id:给事务通知起一个唯一标识 transaction-manager:给事务通知提供一个事务管理器引用 3、配置AOP中的通用切入点表达式 4、建立事务通知和切入点表达式的对应关系 5、配置事务的属性 是在事务的通知tx:advice标签的内部 isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。 propagation:用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选 择。查询方法可以选择SUPPORTS。 read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。 timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。 rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。 没有默认值。表示任何异常都回滚。 no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回 滚。没有默认值。表示任何异常都回滚。 基于注解的配置方式 相关注解 代码块 1. 2. 3. 4. @Transactional(propagation= Propagation.SUPPORTS,readOnly=true)//只读型事务的配置(查询) @Transactional(propagation= Propagation.REQUIRED,readOnly=false)//读写型事务配置(增删改) @Service("accountService") @Transactional(propagation= Propagation.SUPPORTS,readOnly=true)//只读型事务的配置 public class AccountServiceImpl implements IAccountService{ @Autowired private IAccountDao accountDao; 需要的约束 xml 配置步骤 @Override public Account findAccountById(Integer accountId) { return accountDao.findAccountById(accountId); } //需要的是读写型事务配置 @Transactional(propagation= Propagation.REQUIRED,readOnly=false) @Override public void transfer(String sourceName, String targetName, Float money) { System.out.println("transfer...."); //2.1根据名称查询转出账户 Account source = accountDao.findAccountByName(sourceName); //2.2根据名称查询转入账户 Account target = accountDao.findAccountByName(targetName); //2.3转出账户减钱 source.setMoney(source.getMoney()-money); //2.4转入账户加钱 target.setMoney(target.getMoney()+money); //2.5更新转出账户 accountDao.updateAccount(source); int i=1/0; //2.6更新转入账户 accountDao.updateAccount(target); } } <?xml version="1.0" encoding="UTF-8"?> 代码块 总结 环境搭建 spring 的开发包 相关依赖 spring中基于注解 的声明式事务控制配置步骤 0. 配置spring创建容器时要扫描的包 context:component-scan 配置JdbcTemplate 配置数据源 1、配置事务管理器 DataSourceTransactionManager 2、开启spring对注解事务的支持 tx:annotation 3、在需要事务支持的地方使用@Transactional注解 1. 2. 3. 4. 5. 官网:http://spring.io/ 下载地址: http://repo.springsource.org/libs-release-local/org/springframework/spring 相关注解 org.springframework spring-context 5.0.2.RELEASE org.springframework spring-jdbc 5.0.2.RELEASE org.springframework spring-tx 5.0.2.RELEASE org.springframework spring-test 5.0.2.RELEASE org.aspectj aspectjweaver 1.8.7 用于创建对象的: @Component @Controller @Service @Repository 用于注入数据的: @Autowired @Qualifier @Resource @Value 用于改变作用范围的: @Scope 和生命周期相关的: @PostConstruct @PreDestroy Spring 整合 Junit: 把原有的main方法替换 @RunWith(SpringJUnit4ClassRunner.class) 指定注解类所在地位置 @ContextConfiguration(locations= {"classpath:bean.xml"}) 切面类 @Aspect 切入点 @Pointcut 前置通知 @Before 后置通知 @AfterReturning 异常通知 @AfterThrowing 最终通知 @After 环绕通知 @Around 事务支持 @Transactional AOP 相关术语 数据源 配置 C3P0 数据源 配置 DBCP 数据源 配置 spring 内置数据源 相关标签 相关xml配置 Joinpoint(连接点) Pointcut(切入点) Advice(通知/增强) Aspect(切面)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值