Spring5快速入门,一文贯穿

1 篇文章 0 订阅
1 篇文章 0 订阅

Spring5快速入门,一文贯穿

轻量级开源j2ee应用开发程序

特点:

  • 方便解耦
  • 支持aop
  • 方便程序测试
  • 方便整合框架
  • 降低api开发难度
  • 方便事务操作

IOC 控制反转

把创建对象过程交给spring进行管理,降低耦合度

底层原理

xml解析、工厂模式、反射

过程:

  • 使用xml创建对象
  • 使用xml解析技术解析
  • 通过反射创建对象
    • Class clazz = Class.forName(解析出来的class路径);
    • return (类名)clazz.newInstance();

IOC容器底层就是对象工厂

spring提供IOC容器实现的两种方式(两个接口):

1.BeanFactory: (加载配置文件的时候不会创建对象,使用的时候才创建对象)

​ IOC容器基本实现方式,是spring内部使用的接口,不提供开发人员使用

2.ApplicationContext(加载配置文件的时候就创建对象)

​ 是beanfactory的子接口,提供更多工能,供开发人员使用。

​ 实现类:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xkK0axEE-1626155346282)(…/…/AppData/Roaming/Typora/typora-user-images/image-20210712180533330.png)]

Bean管理
基于xml方式

创建对象

(1)bean标签

​ id:全局唯一标识

​ class:类全路径

属性注入

set方法注入
<!--(2)spring方式: set方法注入属性-->
<bean id="book" class="com.zero.spring5.Book">
    <!--使用property完成属性注入
        name:类里面属性名称
        value:向属性注入的值
    -->
    <property name="bname" value="Hello"></property>
    <property name="bauthor" value="World"></property>
</bean>

有参构造
<!--(2)spring方式:有参数构造注入属性-->
<bean id="orders" class="com.atguigu.spring5.Orders">
    <constructor-arg name="oname" value="Hello"></constructor-arg>
    <constructor-arg name="address" value="China!"></constructor-arg>
</bean>
注入空值
<bean id="book" class="com.atguigu.spring5.Book">
    <!--(1)null值-->
    <property name="address">
        <null/><!--属性里边添加一个null标签-->
    </property>
    
    <!--(2)特殊符号赋值-->
     <!--属性值包含特殊符号
       a 把<>进行转义 &lt; &gt;
       b 把带特殊符号内容写到CDATA
      -->
        <property name="address">
            <value><![CDATA[<<南京>>]]></value>
        </property>
</bean>

注入外部Bean
<!--1 service和dao对象创建-->
<bean id="userService" class="com.zero.spring5.service.UserService">
    <!--注入userDao对象
        name属性:类里面属性名称
        ref属性:创建userDao对象bean标签id值
    -->
    <property name="userDao" ref="userDaoImpl"></property>
</bean>
<bean id="userDaoImpl" class="com.zero.spring5.dao.UserDaoImpl"></bean>

注入内部类和级联赋值
<!--内部bean-->
    <bean id="emp" class="com.zero.spring5.bean.Emp">
        <!--设置两个普通属性-->
        <property name="ename" value="Andy"></property>
        <property name="gender" value=""></property>
        <!--设置对象类型属性-->
        <property name="dept">
            <bean id="dept" class="com.zero.spring5.bean.Dept"><!--内部bean赋值-->
                <property name="dname" value="宣传Fehead"></property>
            </bean>
        </property>
    </bean>

<!--方式一:级联赋值-->
    <bean id="emp" class="com.zero.spring5.bean.Emp">
        <!--设置两个普通属性-->
        <property name="ename" value="Andy"></property>
        <property name="gender" value=""></property>
        <!--级联赋值-->
        <property name="dept" ref="dept"></property>
    </bean>
    <bean id="dept" class="com.zero.spring5.bean.Dept">
        <property name="dname" value="公关Fehead"></property>
    </bean>

 <!--级联赋值-->
    <bean id="emp" class="com.zero.spring5.bean.Emp">
        <!--设置两个普通属性-->
        <property name="ename" value="jams"></property>
        <property name="gender" value=""></property>
        <!--级联赋值-->
        <property name="dept" ref="dept"></property>
        <property name="dept.dname" value="技术Fehead"></property>
    </bean>
    <bean id="dept" class="com.zero.spring5.bean.Dept">
    </bean>
注入集合属性
<!--(2)在 spring 配置文件进行配置-->
    <bean id="stu" class="com.zero.spring5.collectiontype.Stu">
        <!--数组类型属性注入-->
        <property name="courses">
            <array>
                <value>java课程</value>
                <value>数据库课程</value>
            </array>
        </property>
        <!--list类型属性注入-->
        <property name="list">
            <list>
                <value>张三</value>
                <value>李四</value>
            </list>
        </property>
        <!--map类型属性注入-->
        <property name="maps">
            <map>
                <entry key="JAVA" value="java"></entry>
                <entry key="Python" value="php"></entry>
            </map>
        </property>
        <!--set类型属性注入-->
        <property name="sets">
            <set>
                <value>MySQL</value>
                <value>Redis</value>
            </set>
        </property>
</bean>

注入对象类型集合
    <!--创建多个course对象-->
    <bean id="course1" class="com.zero.spring5.collection.Course">
        <property name="cname" value="Spring5框架"></property>
    </bean>
    <bean id="course2" class="com.zero.spring5.collection.Course">
        <property name="cname" value="MyBatis框架"></property>
    </bean>
    
   	<!--注入list集合类型,值是对象-->
       <property name="courseList">
           <list>
               <ref bean="course1"></ref>
               <ref bean="course2"></ref>
           </list>
       </property>

FactoryBean

spring中有两种类型的bean,一种是普通的bean,一种是FactoryBean

  • 普通的Bean:在配置文件中定义的bean类型就是返回类型
  • 工厂Bean:在配置文件定义bean类型可以和返回的类型不一样
public class MyBean implements FactoryBean<User>{
    @Override
    public Object getObject() throws Exception {
        return null;
    }
    @Override
    //确定返回的类型
    public Class<?> getObjectType() {
        User t = new User(){{
            setId(1);
        }}
        return t;
    }
    @Override
    public boolean isSingleton() {
        
    }
}

//test
<bean id="myBean" class="com.atguigu.spring5.collectiontype.myBean">
    
ApplicationContext context = new ClassPathXmlApplicationContext("example.xml");
User user = context.getBean("myBean",User.class);
System.out.println(user);

Bean的作用域

spring中默认创建的对象是单实例的(对象地址相等)。

<bean id="myBean" class="com.zero.spring5.collectiontype.myBean" scope="singleton"

多实例对象创建

<bean id="myBean" class="com.zero.spring5.collectiontype.myBean" scope="prototype"

scope:

​ singleton:单实例

​ prototype:多实例

​ Requst:一次请求

​ session:一次会话

Bean的生命周期

对象从创建到销毁的过程

(1)通过构造器创建bean实例(无参)

(2)为bean的属性设置值和对其他bean的引用(set)

(3)把bean实例传递给bean后置处理器方法

(3)调用bean的初始化方法(需要进行初始化配置)

​ 在bean类中创建初始化的方法

(3)把bean实例传递给bean后置处理器的方法

(4)获取到bean

(5)当容器关闭的时候,调用bean的销毁方法(配置销毁方法)

​ 在bean类中创建销毁的方法

​ 使用((ClassPathXmlApplicationContext)context).close()方法触发销毁方法,从而销毁对象

创建后置处理器

public class MyBean implements BeanPostProcessor {
     @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("在初始化方法之前执行")
        return bean;
    }

    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("在初始化方法之后执行")
        return bean;
    }
}
//xml中配置这个类
<bean id="myBean" class="com.atguigu.spring5.collectiontype.myBean">

xml自动装配

根据指定装配规则(属性名或者属性类型)进行自动装配

<bean id="myBean" class="com.atguigu.spring5.collectiontype.myBean" autowire="byName">
<bean id="bean" class="com.atguigu.spring5.collectiontype.myBean" autowire="byName"> //实现了根据名称将bean对象自动注入myBean对象中
//根据类型自动装配也是一样,不过当有多个相同类型的实例,就会报错

导入外部属性文件

<context:property-placeholder location="classpath:jdbc.properties"/>  //引入了jdbc.properties文件
<bean id="datasource" class= "com.alibaba.druid.pool.DruidDataSource">
	<property name="driverClassName" value = "${prop.driverClass}"></property>
    <property name="url" value = "${prop.url}"></property>
    <property name="username" value = "${prop.username}"></property>
    <property name="password" value = "${prop.password}"></property>
</bean>


基于注解方式

@service

@componet

@controller

@reposity

注入对象

​ @Autowired:根据类型自动装配

​ @Qualifier:根据属性名进行注入和autowired配合使用

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

注入普通类型:

​ @Value

组件扫描配置

//设置哪些内容不进行扫描
<context:component-scan base-package=“com.zero">
  	<context: exclude-filter type="annotation"
                             expression="com.zero.Controller"/>
                                               
</context:component-s>

//设置扫描哪些包
<context:component-scan base-package=“com.zero" use-default-filters="false">
  	<context: include-filter type="annotation"
                             expression="com.zero.Controller"/>
                                               
</context:component-s>                                                     

AOP 面向切面

不修改源代码进行功能增强

底层原理
1.AOP底层使用动态代理

​ 有接口的情况(对接口实现类进行增强的情况):使用jdk动态代理

​ 创建一个接口实现类的代理对象,

​ 使用jdk中Proxy类中的newProxyInstance创建代理方法

​ 参数1:类加载器

​ 参数2:增强方法所在的类,这个类实现的接口,支持多个接口

​ 参数3:实现InvocationHandler,创建代理对象,写增强的方法

public class JDKProxy {
    
    public static void main(String[] args) {
        //需要增强方法实现的接口,可以是多个
        Class[] interfaces = {UserDao.class};
        UserDao o = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader()/*类加载器*/, interfaces/*增强方法实现的接口*/, new UserDaoProxy(new UserDaoImpl()) /*代理对象类*/);
        System.out.println(o.add(1, 2));
    }
}
class UserDaoProxy implements InvocationHandler{

    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 invoke = method.invoke(obj, args);

        //方法之后
        System.out.println("方法执行之后执行。。。。。。");
        return invoke;
    }
}

​ 没有接口的情况:使用CGLIB动态代理

​ 创建当前类子类的代理对象

AOP术语
连接点

类里面的哪些方法可以被增强,这些方法就叫做连接点

切入点

实际真正被增强的方法叫切入点

通知(增强)

实际被增强的逻辑部分叫通知

通知有多种类型

​ 前置通知

​ 后置通知

​ 环绕通知

​ 异常通知

​ 最终通知

切面

是一个动作,把通知应用到切入点的过程叫切面

AOP操作

基于AspectJ实现AOP操作

切入点表达式

表明对哪个类中的哪个方法进行增强

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

execution(*com.zero.service.UserDao.add(1,2))

基于注解方式实现

1.创建一个类,在类里面定义方法,实现其增强

2.创建增强类(编写增强逻辑)

​ 在增强类上面加上@Aspect注解 生成代理对象

3.配置文件中开启生成代理对象

4.配置不同类型的通知

​ 在增强类作为通知的方法上面添加通知类型注解并写切入点表达式

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

//增强类
@Component
@Aspect
public class UserProxy {
    //前置通知
    @Before(value = "execution(* com.example.spring5.service.aop.User.add(..))")
    public void before() {
        System.out.println("before.......");
    }
    //在方法执行后
    @After(value = "execution(* com.example.spring5.service.aop.User.add(..))")
    public void after() {
        System.out.println("after");
    }
    //在方法返回值返回之后
    @AfterReturning(value = "execution(* com.example.spring5.service.aop.User.add(..))")
    public void afterRtreuning() {
        System.out.println("afterReturning");
    }
    //异常
    @AfterThrowing(value = "execution(* com.example.spring5.service.aop.User.add(..))")//
    public void afterThrowing() {
        System.out.println("afterThrowing");
    }
    @Around(value = "execution(* com.example.spring5.service.aop.User.add(..))") //方法执行前和执行后
    public void arount(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("增强前...");
        proceedingJoinPoint.proceed();//执行增强的方法
        System.out.println("增强后...");
    }

}

公共切入点抽取
 //切入点抽取
    @Pointcut(value = "execution(* com.example.spring5.service.aop.User.add(..))")
    public void point() {
        
    }

    //前置通知
    @Before(value = "point()")
    public void before() {
        System.out.println("before.......");
    }

事务管理:

@Transitional事务参数

propagation:参数传播

  • REQUEIRED:如果有事务在运行当前方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行
  • REQUEIRED_NEW:当前方法必须启动新事务,并在它自己的事务内运行,如果有事务正在运行,应该将它挂起
  • SUPPORTS:如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不运行在事务中
  • NOT_SUPPORTS:当前方法不应该运行在事务中,如果有运行的事务,将它挂起
  • MANDATORY:当前的方法必须运行在事务内部,如果没有正在运行的事务就抛出异常
  • NEVER:当前的方法不应该运行在事务中,如果有运行的事务,就抛出异常
  • NESTED:如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则就启动一个新的事务,并在它 自己的事务内运行

ioslation:事务隔离级别

三个读的问题:

  • 脏读:一个未提交的事务读取到了另一个未提交事务的数据
  • 不可重复读:一个未提交事务读取到了另一个已提交事务的数据
  • 幻读:一个未提交事务读到了一个已经提交事务添加的数据

四个隔离级别:

  • READ UNCOMMITED:读未提交
  • READ COMMITED:读已提交
  • REPEATABLEED:可重复读(mysql默认,解决脏读和不可重复读)
  • SERIALIZABLE:串行化

timeout:超时时间

事务需要在一定时间内提交,如果不提交就进行回滚

readonly:是否只读

默认为false,通过设置为true来限制我们只读

rollbackFor:回滚

设置查询哪些异常进行事务回滚

norollbackFor

设置出现哪些异常不进行事务回滚

新特性

  • 默认的日志框架从log4j变为log4j2
  • 支持@Nullable:可以用在方法,属性,参数上,方法返回值可以为空,属性值可以为空,参数值可以为空
  • 支持函数式编程
  • 支持junit5
  • webflux: 一个异步非阻塞的框架
    • springmvc是命令式编程,springwebfux是异步响应式编程
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值