Spring

Spring 学习

Spring IOC 的介绍

  • 问题
    在使用MVC的结构体系来完成后台功能代码的声明时,在一定程度上降低了代码的冗余,但是层与层之间的耦合性过高,造成代码升级维护特别麻烦,比如,某天业务层某个类文件需要替换为新的类文件,那么,控制层所有调用该业务类的代码需要全部修改为调用新的业务类。
  • 解决
    将层与层对象之间的关系进行解耦,由直接变为间接,简而言之,就是Spring IOC 用来解决层与层之间耦合读过高的问题。
  • 原理
    化直接为间接。比如A类要调用B类中的方法,变为A类调用C类,从C类中获取B对象,这个过程Spring帮我们做。

Spring IOC 创建对象的三种方式

1、获取Spring容器对象
        //创建容器对象--解析XML
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationcontext.xml");
2. 通过构造器方式
<!--
    无参构造器 
    特点:Spring容器默认使用无参构造方式创建对象
    使用:在配置文件中直接使用bean标签配置即可,无需过多声明
	-->
<bean id="stu" class="Student"></bean>
 <!--有参数的构造器
    特点:Spring容器对根据配置调用的有参构造器创建一个带有初始化数据的对象
    使用:constructor-arg:使用bean的字标签来声明调用的构造器的形参的个数
    一个字标签表示一个参数
    属性:index:参数的下标
          type:参数的类型,全限定路径
          name:参数的形参名
          value:参数要给的值
    -->
    <bean id="stu2" class="com.bjsxt.pojo.Student">
        <constructor-arg index="0" type="java.lang.Integer" name="sid" value="1"></constructor-arg>
        <constructor-arg index="1" type="java.lang.String" name="sname" value="张三"></constructor-arg>
    </bean>
3、通过属性注入的方式(get/set)
  <!--创建student的bean对象-->
    <!--
    属性注入方式
    特点:相当于创建一个空对象然后使用set方法赋值
    使用:
    property:在bean标签下使用子标签property,表示调用set方法给某个属性赋值
    属性:name:要赋值的属性名
          value:值
    -->
    <bean id="stu3" class="Student">
        <property name="sid" value="2"></property>
        <property name="sname" value="小王"></property>
    </bean>
4、工厂模式
    <!--动态工厂-->
        <bean id="factory" class="StudentFactory"></bean>
        <!--生产Student对象-->
        <bean id="stu4" factory-bean="factory" factory-method="newIntance"></bean>
    <!--静态工厂-->
    <!--可以理解为静态方法直接用类名调用-->
        <bean id="stu5" class="StudentFactory2" factory-method="newIntance"></bean>

Spring IOC的依赖注入DI

  • DI依赖的使用流程
    1、将依赖责任链上的所有的对象都配置为bean
    2、根据依赖关系完成对象之间的组装配置
  • 实现方式
    1、通过构造器方式
    2、 通过set方法方式
  <!--配置学生bean对象-->
    <bean id="stu" class="Student">
        <!--构造器方式-->
        <!--<constructor-arg index="0" name="teacher" type="Teacher" ref="tea" ></constructor-arg>-->
        <!--set方式-->
        <property name="teacher" ref="tea"></property>
        <property name="sname" value="张三"></property>
        <property name="sid" value="1"></property>
    </bean>
    <bean id="tea" class="com.bjsxt.pojo.Teacher">
        <property name="tid" value="2"></property>
        <property name="tname" value="刘老师"></property>
    </bean>

Spring IOC 创建对象的单例多例方式

  • 问题?
    由于Spring容器对象底层使用的是map集合存储的bean对象,对map集合按照同一个键名获取数据,获取的是同一个,也就说按照同一个键名从Spring容器中获取的都是同一个对象,那么如果我们希望相同的键名获取的对象每次都不一样,怎么实现?

  • 解决
    不要在Spring容器对象创建的时候,就完成对象的初始化创建,而是变为,从Spring容器中获取的时候才创建,每次获取都重新创建。

  • 代码展示

    <!--
    单例模式:默认模式,在bean标签上使用scope属性,默认值为singleton
    多例模式:在bean标签上使用scope属性设置,值为prototype
    -->
    <bean id="stu" class="Student" scope="singleton"></bean>
    <bean id="tea" class="Teacher" scope="prototype"></bean>

SpringIOC 的自动注入

1、根据bean的ID和属性名一致的规则
2、根据bean的类型和属性的类型一致的规则
3、根据构造器形参的类型和bean的类型一致的规则

Spring AOP 介绍学习

  • 引入
    当我们需要对某一个功能方法,进行升级时,这个代码时小王写的,他已经辞职,并且现在我需要去升级这段功能,给我造成的很大的烦恼;一是、代码很难看懂,二是、新增的代码可能与之前会有冲突,如变量名、耦合性问题等。那么有没有什么方法,能不能不改变原有的代码基础上,来使我们完成代码的升级呢?
  • 解决
    1、使用接口的方式实现
    对象A和对象B
    对象A和对象B共同实现C接口,在新的对象B中重写test方法,然后调用A类的方法+要升级代码。此方法耦合过高,多次升级,就要改很多代码。
    2、升级

SpringAOP的专业概念

1、真实对象:要进行功能扩展的对象
2、代理对象:完成功能扩展的对象
3、切点:要进行功能扩展的方法  execution(* com.ssm.service.impl.*.*(..))

SpringAOP的SchemaBase方式实现

1、前置通知类,实现MethodBeforeAdvice接口, 重写before方法,在before方法中声明扩展前的逻辑代码。
/**
     * 
     * @param method 切点方法对象
     * @param objects 参数
     * @param o 真实对象
     * @throws Throwable
     */
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("MyBefore.before:我是扩展前");
    }
2、后置通知类,实现AfterReturningAdvice接	口,重写after方法,并在after方法中声明扩展后的逻	辑代码。
/**
     * 
     * @param o 代理对象
     * @param method 切点方法对象
     * @param objects 参数
     * @param o1 真实对象
     * @throws Throwable
     */
    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("MyAfter.afterReturning:我是扩展后");
    }
3、异常类,实现异常接口ThrowsAdvice,重写afterThrowing方法。
4、环绕通知,实现MethodInterceptor接口,重写invoke方法。
<!--配置Student的bean-->
        <bean id="stu" class="com.longlong.pojo.Student"></bean>

    <!--配置扩展bean-->
        <!--配置前置通知-->
        <bean id="before" class="com.longlong.advice.MyBefore"></bean>
        <!--配置后置通知-->
        <bean id="after" class="com.longlong.advice.MyAfter"></bean>
        <!--配置环绕bean-->
        <bean id="round" class="com.longlong.advice.Myround"></bean>
        <!--配置异常信息-->
        <bean id="thorw" class="com.longlong.advice.MyThrow"></bean>

    <!--配置组装规则-->
        <aop:config>
            <!--声明切点-->
            <aop:pointcut id="mp" expression="execution(* com.longlong.pojo.Student.testStudent(String,int))"/>
            <!--前置通知-->
            <aop:advisor advice-ref="before" pointcut-ref="mp"></aop:advisor>
            <!--后置通知-->
            <aop:advisor advice-ref="after" pointcut-ref="mp"></aop:advisor>
            <!--环绕通知-->
            <aop:advisor advice-ref="round" pointcut-ref="mp"></aop:advisor>
            <!--异常通知-->
            <aop:advisor advice-ref="thorw" pointcut-ref="mp"></aop:advisor>
        </aop:config>

SpringAOP的Aspectj方式实现

Java类MyAdvice

//前置通知
    public void before(){
        System.out.println("我是前置通知");
    }
    //后置通知
    public void after(){
        System.out.println("我是后置通知");
    }
    //环绕通知
    public void myRound(ProceedingJoinPoint pp) throws Throwable {
        //环绕前
        System.out.println("环绕前");
        //放行
        Object proceed = pp.proceed();
        //环绕后
        System.out.println("环绕后");
    }
    //异常通知
    public void myThrow(Exception e){
        System.out.println("异常通知"+e.getMessage());
    }
<!--配置学生的bean-->
    <bean id="stu" class="com.longlong.pojo.Student"></bean>
    <!--配置通知bean-->
    <bean id="advice" class="com.longlong.advice.MyAdvice"></bean>
    <!--配置组装规则-->
    <aop:config>
        <aop:aspect ref="advice"><!--声明通知bean的ID-->
            <!--声明切点-->
            <aop:pointcut id="mp" expression="execution(* com.longlong.pojo.Student.testStudent())"/>
            <!--声明前置扩展方法-->
            <aop:before method="before" pointcut-ref="mp"></aop:before>
            <!--声明后置-->
            <aop:after method="after" pointcut-ref="mp"></aop:after>
            <!--配置环绕通知-->
            <aop:around method="myRound" pointcut-ref="mp"></aop:around>
            <!--异常通知-->
            <aop:after-throwing method="myThrow" pointcut-ref="mp" throwing="e"></aop:after-throwing>
        </aop:aspect>
    </aop:config>

Acspectj和SchemaBased的异同

1、相同点
在不修改源码的情况下都能实现功能的扩展。
2、不同点
(1)SchemaBased方式基于接口来区别前置和后置和环绕和异常通知的,而AspectJ方式是在配置文件中使用标签来区分。
(2)AspectJ方式在配置中的配置方式发现其切点的声明以及对应的通知组装中,切点只在Aop:aspect标签下有效。而SchemaBased方式声明的切点在全局有效.SchemaBased的切点的通用性比AspectJ方式要好。
(3)参数方面,SchemaBased相对于有无参数来说,更加方便使用。

Spring AOP之代理设计模式

1、静态代理
	由程序员自己写。
2、动态代理
	(1)jdk动态代理--基于接口 (默认)
public interface MyInterface {
    //声明功能方法
    void testStudent();
}
public class Myjdk implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("扩展前");
        Student student = new Student();
        student.testStudent();
        System.out.println("扩展后");
        return null;
    }
}
public class TestProxyJDK {
    public static void main(String[] args) {

        //使用jdk动态代理获取Student对象的代理对象
        MyInterface myInterface = (MyInterface) Proxy.newProxyInstance(
                TestProxyJDK.class.getClassLoader(), //类加载器,加载动态生成的代理对象
                new Class[]{MyInterface.class},//动态生成的代理对象要实现的接口
                new Myjdk());//动态生成的代理对象自动调用扩展代码 InvocationHandler的实例化对象
        //调用
        myInterface.testStudent();
    }
}

	(2)cglib动态代理--基于继承
public class Student {
    public void testStudent(){
        System.out.println("Student.testStudent:我是学生");
    }
}
public class Mycglib implements MethodInterceptor {

    /**
     *
     * @param o 代理对象
     * @param method 真实方法对象
     * @param objects 参数
     * @param methodProxy 代理方法对象
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib扩展前");
        //调用真实方法
        methodProxy.invokeSuper(o,objects);
        System.out.println("cglib扩展后");
        return null;
    }
}
public class TestSpringCglib {
    public static void main(String[] args) {

        //使用cglib获取动态生成student代理对象
        Enhancer en = new Enhancer();//创建cglib对象
        en.setSuperclass(Student.class);//动态生成的代理对象需要继承的真实对象
        en.setCallback(new Mycglib());//动态生成的代理方法要调用的代码
        Student student = (Student) en.create();//生成代理对象
        student.testStudent();
    }
}
<!-- 开启cglib动态代理-->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>

Spring TX事务

1、XML配置
<!--SpringTX的事务管理-->
        <!--配置事务管理bean-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>

        <!--配置事务管理方法-->
        <tx:advice id="advice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="sel*" read-only="true"/>
                <tx:method name="ins*"/>
                <tx:method name="up*"/>
                <tx:method name="del*"/>
            </tx:attributes>
        </tx:advice>

        <!--配置事务管理的切面-->
        <aop:config>
            <!--声明业务方法的切点-->
            <aop:pointcut id="mp"
                          expression="execution(* com.longlong.service.impl.*.*(..))"/>
            <!--增加事务通知-->
            <aop:advisor advice-ref="advice" pointcut-ref="mp"></aop:advisor>
        </aop:config>

Spring 常用注解

 @Component:使用在普通java类上。
 @Service:使用在业务层类上。
 @Controller:使用在控制层类上,SpringMVC。
 @Resource:jdk官方的注解,不是Spring的注解,会先按照byName的方式注入。
 @Autowired:Spring官方提供的,默认使用byType。
	@Value:用来替换配置文件中的属性注入的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值