暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

spring学习笔记

JAVA不归路 2021-09-09
232

springIOC笔记

环境搭建

导入

commons-logging-1.2

log4j-1.2.16

spring-beans-4.2.4.RELEASE

spring-context-4.2.4.RELEASE

spring-core-4.2.4.RELEASE

spring-expression-4.2.4.RELEASE六个jar包

对应的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 http://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>

备注:此段xml在spring的html/xsd-configuration.html路径下的html中scheam约束中有

bean创建的两种规则

  1. 一.BeanFactory :提供一种延时加载思想来创建bean对象,bean对象什么时候用什么时候创建

    1. 获取容器

      Resource resource = new ClassPathResouce("bean.xml");//创建一个resouce对象。参数为配置文件(xml文件)
      BeanFactory factory = new XmlBeanFactory(resouce);//获取容器,参数为上一步获取的resouce
    2. 根据id获取对象

      ICustomerService customerService = (ICustomerService)factory.getBean("ICustomerService");
  2. ApplicationContext :提供一种立即加载思想来创建bean对象,只要一解析完配置文件,就立即创建bean对象

    1. 获取容器

      ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml" );
    2. 根据id获取对象

      ICustomerService is = (ICustomerService) ac.getBean("ICustomerService");


bean的三种创建方式(修改xml中的配置文件)

  1. 调用默认无参构造函数创建(如果没有无参构造函数,则创建失败)   实际开发中此种方式用的最多

    //XML配置资源,把对象交给spring来创建
    <bean id="ICustomerService" class="com.baidu.service.ICustomServiceImpl"></bean>
     
    //测试类中通过xml获取对象
    ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml" );
    ICustomerService is = (ICustomerService) ac.getBean("ICustomerService");
  2. 使用静态工厂中的方法创建

//配置使用静态工厂创建bean对象
<bean id="staticCustomerService" class="com.baidu.factory.CustomerFactory" factory-method="getCustomerService"></bean>
//id后为类名。class后为工厂的全限定类名,factory-method后为工厂类获取类对象的方法
//测试类中通过xml获取对象
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml" );
ICustomerService is = (ICustomerService) ac.getBeanid("staticCustomerService") ;
  1. 使用实例工厂方法创建

    //配置使用实例工厂创建bean对象
    <bean id="instanceFactory" class="com.baidu,factory.InstanceFactory" ></bean>
    //先创建工厂对象实例
    //id后为工厂类(名字可以随便起的,但要有意义),class后为工厂的全限定类名
    <bean id="instanceFactory" factory-bean="InstanceFactory"
         factory-method="getICustomerService" ></bean>
    //创建此实例用factory-bean对象里面的getICustomerService方法
    //id为实例类名,factory后为工厂类名,factory-method后为工厂类的方法 :根据此工厂类的方法创建实例类
    ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml" );
    ICustomerService is = (ICustomerService) ac.getBeanid="staticCustomerService" ;

    bean的作用范围

    <bean id="ICustomerService" scope="prototype" class="com.baidu.service.ICustomServiceImpl"></bean>

    它可以通过bean的配置文件来调整作用范围

    singleton :单例的(默认值)

    prototype :多例的(当我们让spring接管struts2的action创建时,action必须创建此值)

    request :一次请求和当前请求的转发

    session :一次会话

    globalsession :作用范围是一次全局会话

    bean的生命周期

    涉及bean标签的两个属性:

    init-method

    destory-method

<bean id="ICustomerService" scope="prototype" init-method="init" destroy-method="destory" class="com.baidu.service.ICustomServiceImpl"></bean>

单例:

出生:容器创建的时候对象出生

ClassPathXmlApplicationContext  ac  = new ClassPathXmlApplicationContext("bean.xml" );

活着:容器在对象就一直存在

ICustomerService is = (ICustomerService) ac.getBeanid="staticCustomerService" 死亡:容器被销毁了对象就被销毁了

ac.close();

//销毁容器  由于ApplicationContext对象没有close方法,所以不能使用多态

多例:

出生:每次使用的时候创建对象

ICustomerService is = (ICustomerService) ac.getBeanid="staticCustomerService" ;

活着:只要对象在使用中就一直活着

死亡:当对象长时间不使用,并且没有别的对象引用时,由java的垃圾回收器回收

spring的依赖注入三种方式

  1. 使用构造函数注入

  2. 涉及的标签:constructor-arg

    1. 标签的属性:

        type:指定参数的类型

      index:指定参数的索引位置,从0开始

      name:指定参数的名称 (常用)

      ==========上面三个属性是指定给哪个参数赋值,下面两个属性指定赋什么值

      value:指定基本数据类型或String类型

      ref:指定其他bean类型的数据

      标签出现的位置:写在bean标签的内部

      <bean id="customerService" class="com.baidu.service.CustomerServiceImpl">
      <constructor-arg name="driver" value="com.baidu.jdbc.Driver"></constructor-arg>
      第一个参数为成员变量,第二个为变量的值,需要类提供一个有参的构造函数
      <constructor-arg name="today" ref="now"></constructor-arg></bean>
      <bean id="now" class="java.util.Date"></bean>//其他bean类型


  3. 使用set方法注入

    涉及的标签:property

    标签的属性:

    name:指定set方法的名称

     ==========上面属性是指定给哪个参数赋值,下面两个属性指定赋什么值

    value:指定基本数据类型或String类型

    ref:指定其他bean类型的数据

    标签出现的位置:写在bean标签的内部

  1. <bean id="customerService" class="com.baidu.service.CustomerServiceImpl">
    <property name="driver" value="com.mysql.jdbc.Driver"> </property>
    第一个参数为方法的名称(set后面的,首字母改小写),第二个参数为设置的值
    </bean>
    1. 基本类型和String类型

    2. 其他bean类型(必须在spring的配置文件中出现过的bean)

    3. 复杂类型(集合类型) !!!结构相同,标签可以互换

    4. 使用注解注入(注入的数据类型有3类:)

      <bean id="customerService" class="com.baidu.service.customerService">
      <property name="myArray">
      <array> //或者是List <list>
      <value>AAA</value>
      < value>CCC</value>
      <value>BBB</value>
      ` </array>
      </property>
      <property name="myList">
      <list>
      <value>AAA</value>
      <value>CCC</value>
      <value>BBB</value>
      ` </list>
      </property>
      <property name="myMap">
      <map>
      <entry key="TA" value="AAA"></entry>
      <entry key="TB>
      <value>BBB</value>
      </entry>
      ` </map>
      </property>
      <property name="myMap">
          <prop key="TA">AAA</prop>
      ` </property>
      </property>
      </bean>


Spring基于注解的IOC配置(导入aop.jar包)  没有复杂类型的注解(集合类型)

需要导入另一个shcema约束

<?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:context="http://www.springframework.org/schema/context" 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"> <!-- bean definitions here -->
</beans>

用于创建bean对象的注解

@Component

作用:相当于配置了一个bean标签

//<bean id="" class=""></bean>

出现位置:接口,类,enum,。。上面

属性:value   含义是指定bean的id,当不写时,它有默认值,默认值时是:当前类的短名首字母小写

由此注解衍生的三个注解:

@Controller  一般用于表现层注解

@Service       一般用于业务层

@Repositort  一般用于持久层 @Repositort("customerDaoImpl")

设置bean的id

它们和@Component的作用及属性都是一样的导入之后需要告知spring 再创建容器时要扫描的包,当配置了此标签之后,spring创建容器就会区指定的包及其子包下找对应的注解

标签是再一个context的名称空间里,所以必须先导入context名称空间

 <context:component-scan base-package="com.baidu"><context:component-scan >
在xml中告知spring需要扫描的包


## 用于注入数据的注解

@Autowired

作用:自动按照类型注入,只要有唯一的类型匹配就能注入成功。

如果注入的bean在容器中类型不唯一时,它会把变量名称作为bean的id,在容器中查找,找到后也能注入成功

如果没有找到一致的bean的id,则报错

当我们使用注解注入时,set方法就不是必须的了

@Qualifier    

 注入类成员时需要将@Autowired写在其上面

作用: 在自动按照类型注入的基础之上,再按照bean的id注入.它再给类成员注入数据时,不能独立使用,但是再给方法的形参注入数据时,可以独立使用 属性: value : 用于指定bean的id

@Resource 作用:直接按照bean的id注入。

属性:name 用于指定bean的id    name不能省略,value可以省略

以上三个注解都用于注入其他bean类型,

@Value     它可以借助spring的el表达式读取properties文件中的配置

作用:用于注入基本类型和String类型数据

属性: value  用于指定要注入的数据


用于改变作用范围的注解

@Scope  作用:改变bean的作用范围

 属性 value : 用于指定bean的作用范围取值与xml中的scope属性取值是一样的。singleton(单例)

prototype(多例)

request  session globalsession

和生命周期相关的注解

@PostConstruct 作用:用于指定初始化方法  相当于init-method @PreDestory 作用:用于指定销毁方法  相当于destory

spring的新注解

@configuration  此注解表示将此类看作spring的配置类
创建一个spring类,作用相当于bean.xml

@ComponentScan({"com.baidu"})

//此注解作用表示spring在创建容器前读取此包下Annotation,里面的参数为注解存在的包,可以传一个String数组


public class SpringConfiguration{

@bean(name="runner")

//它是把方法的返回值存入spring容器中。该注解有一个属性name 用于指定bean的id,当不指定时有默认值,为方法名称

public QueryRunner createQueryRunner(DataSource dataSource){
return new QueryRunner(dataSource);
}
}

@Bean(name="runner")

//它是把方法的返回值存入spring容器中。该注解有一个属性,name:用于指定bean的id。当不指定时它有默认值,默认值是方法的名称。

@bean
public DataSource createDataSource(){
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.set("jdbc相关的配置信息")
return ds;
}
//后面创建容器需要用到bean.xml用另一个类代替

ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);

//里面传配置信息的字节码文件

@import(Class<T>[] c )

//里面传一个类的class文件,表示加载此类

@Value("${jdbc.url}")

//表示读取配置文件里面的key为此字符串的value并且赋值给变量

private String url;
@Configuration//它就是把当前类看成是spring的配置类
@ComponentScan({"com.baidu"})
@Import({JdbcConfig.class})//导入其他配置类

@PropertySource("classpath:config/jdbcConfig.properties")

// 表示加载此配置文件的内容

public class SpringConfiguration {}

@Bean

//在spring4.3.2之前没有解析器,所以需要自己创建,4.3.5后自带,不用自己创建

public static PropertySourcesPlaceholderConfigurer createPropertySourcesPlaceholderConfigurer(){
return new PropertySourcesPlaceholderConfigurer();
}

(@Qualifier("ds1")DataSource dataSource

//方法的参数上面

//当bean返回多个同类型的数据源时,哪个bean的id与数据源变量名一致就用哪一个,如果没有一致的,可以用@Qualifier注入dataSource的id
spring整合junit
//第一步:拷贝spring-test-4.2.4.RELEASE.jar
//第二步:使用junit提供的一个注解,把原有的main函数替换掉,换成spring提供的
@RunWith(SpringJUnit4ClassRunner.class) 这个注解可以替换junit原有的main函数
//第三步:使用spring提供的注解告知spring,配置文件或注解类所在的位置
@ContextConfiguration(classes={SpringConfiguration.class}) 如果时纯注解使用class 是xml使用location={"classpath:bean.xml"}
//要换的类:SpringJunit4ClassRunner


================================

动态代理

作用:在不改变源码的基础上,对已有方法进行增强(它是AOP思想的实现技术) 分类:基于接口的动态代理:

        要求:被代理类最少实现一个接口

         涉及的类:Proxy

        创建代理对象的方法:

            new ProxyInstance(ClassLoader,Class[],InvocationHandler)

参数的含义:

        ClassLoader:类加载器,和被代理对象使用相同的方法,一般都是固定写法          People.getClass().getClassLoader()

        Class[] : 字节码数组,和被代理对象实现相同的接口(要求代理对象和被代理对象实现相同的接口),一般都是固定写法 People.getClass().getInterface()            InvocationHandler: 它是一个接口,就是用于我们提供增强代码的,我们一般都是写一个该接口的实现类,该实现类也可以是匿名内部类

        它的含义就是如何代理,谁用谁写(执行被代理对象的任何方法都会经过该方法),需要实现invoke方法

        invoke(Object proxy,Method method,Object[] args)

        Object proxy: 代理对象的引用,不一定每次都用

        Method method:当前执行的方法

        Object[] args:当前执行方法所需要的参数

        返回值:当前执行方法的返回值

基于子类的动态代理

要求:被代理对象不能是最终类,不能被final修饰
提供者:第三CGLib,需要导入两个jar包(asm.jar,cglib.jar)
涉及的类:Enhancer
创建代理对象的方法:create(Class,Callback);
参数的含义:
Class:被代理对象的字节码
Callback:如何代理.它和InvocationHandler的作用一样,它也是一个接口,我们一般使用该接口的子类接口MethodInterceptor
在使用时我们也是创建该接口的匿名内部类
执行被代理对象的任何方法都会经过该方法,它和基于接口动态代理的invoke方法的作用是一模一样的
Enhancer.create(other.getClass,new MethodIntercepto(){
} )
方法的参数:
前面三个和invoke方法的参数含义和作用都是一样的
MethodProxy methodProxy:当前执行方法的代理对象,一般不用
new MethodInterceptor(){
public Object intercept(Object proxy,Method method,Object[] args,MethodProxy args2) throws Throwable{

}
}

spring的aop

//导入aop的名称空间,并且使用aop:config开始aop的配置
<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"
   xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
把通知类交给spring来管理
       <bean id="logger" class="com.baidu.utils.Logger"><bean>
  配置service 基于xml的aop配置步骤:想要使用spring的aop,必须导入aop的jar包
   <bean id="customerService" class="com.baidu.service.impl.CustomerServiceImpl"></bean>
      //使用aop:config开始aop的配置
     <aop:config>
    使用aop:aspect配置切面,id属性用于给1切面提供一个唯一标识 ref:属性,用于应用通知Bean的id
        <aop:aspect id="logAdvice" ref="Logger">  
  ** 配置通知的类型,指定增强方法何时执行,method属性:用于指定增强方法的名称,pointcut属性:用于指定切入点表达式
全匹配方式:  
 切入点表达式:关键字:execution(表达式) 表达式写法: 访问修饰符 返回值 包名.. 类名 方法名(参数列表)
访问修饰符可以省略
返回值可以用通配符,表示任意返回值 通配符是*
包名可以使用通配符,表任意包,但是有几个包就需要写几个*   *.*.*.*
包名可以使用.. 表当前包及其子包 com.. *..
类名和方法名都可以使用通配符: *.*()
参数列表可以使用具体类型,来表示参数类型
基本类型直接写类型名称:int
引用类型必须是包名.类名 java.lang.Integer
参数列表可以使用通配符 * 表示任意参数类型,但是必须要有参数
也可以使用 .. 表示有无参数均可,有参数可以是任意类型
全通配方式: * *..*.*(..)
        **/  
<aop:before method="printLog"
pointcut="execution(public void com.baidu.service.impl.CustomerServiceImpl.savaCustomer )">
          </aop:before>
     </aop:config>


springAOP的XML和注解

1.导入jar包aopalliance-1.0.jar   aspectjweaver-1.8.7.jar spring-aop-4.2.4.RELEASE.jar   spring-aspects-4.2.4.RELEASE.jar

第一步:
创建通知类,将通知类交给spring来管理  <bean id="logger" class="com.baidu.logger">
第二步:
导入aop的命名空间,并且使用aop:config开始aop的配置
<aop:config>
第三步:使用aop:aspect配置切面,id属性用于给切面提供一个唯一标志,ref属性:用于应用通知bean的id
<aop:aspect id="logAdvice" ref = "logger">
第四步:配置通知类型(前置,后置,异常,最终,环绕),指定增强方法何时执行,method属性:用于指定增强方法的名称
,pointcut属性:用于指定切入点表达式(对哪些方法进行增强) 写法:访问修饰符 返回值 包名.. 类名 方法名(参数列表)>
<aop:before method="printLog" pointcut="execution(* *..*.*(..)" / > 前置通知
<aop:after-returning method="afterReturningPrint" pointcut-ref="切入点表达式"> 后置通知
<aop:after-throwing method="通知的方法" pointcut-ref=""> 异常通知
<aop:after metho="" pointcut-ref=""> 最终通知
<aop:around method="logger类中的方法(环绕通知的方法)" pointcut="pt1">
</aop:aspect>
</aop:config>
    定义通用的切入点表达式,如果是写在了aop:aspect标签内部,则表达式只有当前切面可用
<aop:pointcut expression="execution(* *..*.*(..))" id="pt1"> 写在<aop:config> 标签下表都可用

环绕通知:当配置了环绕通知之后,切入点方法没有执行,而环绕通知里面的方法执行了,由动态代理可知,环绕通知指的是invoke方法,并且里面由明确的方法调用,而我们环绕通知中没有明确切入点方法调用.

解决:
spring为我们提供了一个接口:ProceedingJointPoint,该接口可以作为环绕通知的方法参数来使用
在程序运行时,spring框架会为我们提供该接口的实现类,让我们使用
该接口中有一个方法: proceed() , 它的作用就等同于method.invoke方法,就是明确调用业务层的核心方法
public Object aroundPrintLog(ProceedingJoinPoint pjp){
Object rtValue = null;
try{
//前置通知
rtValue  = pjp.proceed()
//后置通知;
}catch(Throwable t){
异常通知  method
}finally{
sout   //最终通知
}
return rtValue;
}

注解aop

需要导入context名称空间

<context:component-scan base-package="com.baidu" /> //配置扫描的包
<aop:aspectj-autoproxy /> //需要开启spring对aop注解的支持
@Component("logger")  
@Aspect  //写在通知类上,就表示配置了切面
//在类里面的方法配置通知类型 @Before("pt1()") @AfterReturning("pt1()") @AfterThrowing("pt1()") @After("pt1()") @Around
配置切入点表达式
@Pointcut("execution(* *.. *.*(..))")
private void pt1(){}



使用纯注解配置

        //新建一个springConfig类
@Configuration   //该注解表此类是spring配置类
@ComponentScan("com.baidu") //配置要扫描的包
@EnableAspectJAutoProxy  //开aop支持
public class SpringConfiguration{
           
      }


        //需要改拿到容器的main方法

ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfigration.class)

//此处写配置类的字节码文件

ICustomerService cs = (ICustomerService)ac.getBean("customerService")
cs.saveCustomer();





文章转载自JAVA不归路,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论