其他分享
首页 > 其他分享> > Sping整理(一)

Sping整理(一)

作者:互联网

why spring

1.可解决大量的重复创建对象的过程,将对象的创建交给spring。

2.创建对象方式:
1.直接new
2.通过反射 Class class = Class.forName("com.xxx.xxx")
class.newInstance().var

spring 工厂模式

1.工厂模式出现原因:解耦合,由工厂帮助创建对象

2.原理:

获取有需要使用的bean对象

相关方法
getBean()

​ 方式一:直接通过id
​ UserService userServiceImpl = (UserService) applicationContext.getBean("userService");
​ 方式二:指定id和类型,避免强制转换
​ UserService userService1 = applicationContext.getBean("userService", UserService.class);
​ 方式三:只通过类型,该类型必须只有一个bean
​ UserService userService2 = applicationContext.getBean(UserService.class);
getBeanDefinitionNames()
​ 获取xml定义的bean的id数组
​ String[] names = applicationContext.getBeanDefinitionNames();
getBeanNamesForType()
​ 根据类型获得bean的id数组
​ String[] names = applicationContext.getBeanNamesForType(UserService.class);
containsBeanDefinition()

​ 是否包含bean的定义,只能判断id,不能判断别名name
​ boolean userService = applicationContext.containsBeanDefinition("userService");
3.基础实现原理:
​ 通过配置文件获得对象的class文件,再反射调用无参构造进行创建,私有的无参构造也可以。

ps:实体类对象不用spring创建,因为需要数据--->持久层创建

spring注入

1.概念:通过spring工厂及配置文件,对bean对象的成员属性进行赋值。

2.价值:一般赋值方式:get/set ---->存在耦合 注入:解耦合,但还是需要get.set方法

3.方式:

<bean id="student" class="com.boss.leraning.springdemo.bean.Student">
    <property name="age" value="18"></property>
</bean>

4.实现原理:

调用get set 方法:对应着property里面的name 调用setName方法---------->所以也叫set注入

set注入

注入各种类型的成员变量方法

1.注入的成员变量的类型多种,不单只有int 和string ------->用value赋值即可

2.JDK提供的数据类型

3.用户自定义类型

* 一个property标签调用一次set方式
方式一:直接在bean内部定义另一个bean
<bean id="useService "class=" ">
    <property name="useDao">//调用set
         <bean class="userdao"></bean>/创建对象
    </property>
</bean>
//方式二:当userDao需要被别的对象使用
方式一问题:多次创建userDao浪费内存
<bean id="userDao" class=""></bean>
<bean id = "userService">
    <property name="useDao">
        <ref bean="userDao"/>
    </property>
</bean>
//简写方式:
<bean id ="" class="">
    <property name="" value=""></property>
    <property name="" ref=""></property>
</bean>

构造注入

1.通过有参构造方法对成员变量进行赋值--->定义有参构造函数

2.方式

<bean id="",class="">
    <constructor-arg>//一个该标签调用一次构造方法,传递一次参数
        <value></value>
    </constructor-arg>
</bean>

3.构造参数重载

通过控制constructor标签的数量,找到对应的构造函数

对于参数个数相同情况,要通过类型去区分,eg ,name和age
否则会按顺序去构造
<bean id="",class="">
    <constructor-arg type="int" ,value=""></constructor-arg>
</bean>

总结

1.一般多数采用SET注入

反转控制(ioc inverse of Control)

1.控制的概念:对成员变量赋值的控制权-----代码/配置文件+Spring工厂

2.反转控制:将控制权从代码转移到配置文件当中。

依赖注入(dependency injection)

1.依赖:使用到它,需要它----->将它作为成员变量,通过配置文件进行赋值注入

复杂对象

创建复杂对象的方式

<bean id="conn" class="MyFactoryBean"></bean>
//通过getBean("conn")获取到的不是MyFactoryBean,而是它所创建的复杂对象---connection
//通过getBean("&conn")获取到是MyFactoryBean

​ 3.依赖注入例子:

4.实现原理:1.id+class---->获得ConectionFactoryBean----->通过getObject获得conn对象。

创建一次的对象:

1.sqlSessionFactory

2.Dao

3.UserService

需要创建多次的对象:

1.sqlSession

2.Connection

对象的生命周期

对象的各个阶段

1.对于singleton对象

在工厂创建的时候就进行创建
懒初始化:在bean标签当中加入属性lazy-inti="true",也能达到prototype的效果

2.prototype对象

在对象被获取调用的时候,才被创建

配置文件参数化

1.参数化的目地:能够方便后期的维护,将一些经常修改的值,定义到一个property文件当中。通过${kay名}获得值。

例如:

1.新建小配置文件:

2.配置文件的内容:

3.将小配置文件整合spring配置文件

classpath:resouce 和同级的java文件夹下的内容的整合。

自定义类型转换器

1.在注入的时候将String转换为需要注入的属性的类型。

2.在某些情况下Spring定义的类型转换器不满足我们的需求,例如将string类型转化为Date 类型。

内置只支持---”yyyy/MM/dd"的格式

-----------》进行自定义类型转换器

后置处理Bean

BeanPostProcessor(接口):对工厂创建的对象进行进一步的再加工

待重写方法:
   Object postProcessBeforeInitiallization(Object bean String BeanName){
//在创建完对象,待初始化之前进行调用
return bean;//返回加工之后的对象
}

 Object postProcessAfterInitiallization(Object bean String BeanName){
//在初始化完成之后进行调用
return bean;//返回加工之后的对象
}
//如果没有实现初始化操作的化,两个方法没有区别,但是不管有没有进行加工都要将bean对象进行返回。

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

注意 beanPostProcessor会对工厂的所有对象都进行加工,所以前面代码要进行类型判断,instanceof()

代理设计模式

1.javaEE的开发层次当中最重要的是service层

dao--->service--->controller

2.service的功能

性能:业务的开始时间和结束时间之间的差。

日志:谁,何时,做何事

1.代理设计模式概念:通过代理类(proxy)来完成目标类的额外功能,利于目标类的维护。改动额外功能时不用改变目标类

2.

以上代理方法为静态代理为每一个原始类都编写一个代理。

spring 动态代理

本质与静态代理相同

1.导入相关的jar包

方式二(推荐,可以在原始方法的前后都添加额外功能):
实现接口MethodInterceptor中的invoke方法
pucblic class Arround implement MethodInterceptor{
     @override
     //该方法的参数就是所要添加额外功能的原始方法
     public Object invoke(MethodInvocation invocation) Throws Throwsable{
         sout"------"//按自己要求添加额外功能
         Object ret= invocation.proceed();//表示让原始方法运行,以便让额外功能添加在其之后
          return ret;
     }
}
//后步骤与MethodBeforeAdvice相同
该接口的功能比MethodBeforeAdvice更加强大,并且可以通过改变ret,改变返回值。

切入点详解

方法切入点

切入点的位置:决定额外功能加入的位置
<aop:pointcut id="pc" expression="execution(* *(..))"></aop:pointcut>
//切入点函数:execution()
//切入点表达式:execution(* *(..))
第一个* --->修饰符,返回值
第二个*---->方法名
()中的..---->参数个数任意
eg.
* login(String)//方法login,参数一个,如果是非java.lang包中类型写全限定名
* login(String,..)//表示只要第一个参数是String即可,后参数的个数和类型没要求

类切入点

1.使用场景:对于某个类中的所有方法加入额外功能。

2.方式:

//所有包中的userServiceImpl类中的所有方法
<aop:pointcut id="pc" expression="execution(* *..uerServiceImpl.*(..))"></aop:pointcut>

包切入点

定义在某个包下的所有的类的切入点:

语法:
//该包中的所有类的所有的方法
<aop:pointcut id="pc" expression="execution(* com.xxx.xxxx.*.*(..))"></aop:pointcut>
//该包及其子包下的所有类的所有方法,包后多加一个点
<aop:pointcut id="pc" expression="execution(com.xxx.xxxx..*.*(..))></aop:pointcut>
//更具有实战价值

切入点函数

1.作用:执行切入点表达式

2.常用的切入点函数:

execution:功能最为齐全,但是表达式书写麻烦
----->其他的函数进行简化,但是本质还是execution
* args(String String)//关心函数的参数。有2个String参数的都满足
* within(*..userSericeImpl)//用于类或包的切入点,表示所有的UserService这个类
  within(com.xxx.xxx..*)//包及其子包下的所有的类原表达式:execution(* com.xxx.xxx..*.*(..))
* annotation(com.xxx.xxx.log)//具有特殊注解的方法,例如自定义注解log,内部写注解全限名

切入点函数逻辑运算

1.概念:讲多个切入点函数之间进行and或者or运算以满足更为复杂的需求。

and
案例:login 同时参数为2个String 
execution(* login(..)) and args(String String)
注意:与操作不能用于同种类型的切入点函数,不能execution and execution
案例: login 和 register----->用and结果为空 ,应该用or操作
or
案例: login 和 register----->用and结果为空 ,应该用or操作
execution(* login(..)) or execution(* register(..))

AOP编程

AOP概念

本质就是Spring的动态代理,通过代理类为原始类增加额外功能。

好处:利于原始对象的维护。

AOP开发步骤

1.原始对象

2.额外功能

3.切入点

4.组装

切面 :由具有相同性质所共同构成的面。

AOP底层实现原理

待思考的问题:

1.aop如何帮我们创建动态代理对象?

2.为何通过id值获得的是代理对象而不是原始对象?

JDK动态代理

1.复习代理创建的三要素

2.Proxy.NewProxyInstance()方法参数的分析:


3.具体编码实现

public calss TestJDKProxy(){
    public static void main(String[] args)
    {
        //创建原始对象
        private UserService userService = new UserService();
        //通过jdk生产代理对象
       //通过匿名内部类实现接口
 InvocationHandler handler = new InvocationHandler(){
   @override
  public Object invoke(Object proxy , Mehtod method , Object[] args) Throws Throwable{
            //额外功能
      sout."-----Proxy-log-------"
      		//让原始方法运行
      		Object ret=method.invoke(userService,args);
       		retuen ret;  
            }
        }
       UserService userServiceProxy = (UserService)
     Proxy.NewProxyInstance(TestJDKProxy.class.getClassloader,userService.getCalss.getInterface(),handler)//强制转换获得UserService
    }
}

cglib动态代理

1.适用情形:原始类没有实现接口,只一个原始类

2.解决方法:继承原始类

3.编码步骤:

public class TestCglib(){
    public static void main(String [] args){
		//创建原始对象
        private UserService userService;
        //Cglib包自带的方法
        Enhancer.SetClassLoader(TestCglib.class.getClassLoader())//设置创建代理对象时的类加载器,也是借的
        Enhancer.SetSuperClass(userService.getClass())//设置父类的class文件,在jdk当中使用的是接口,这里是直接目标类
        //用内部类实现MethodInterceptor接口,与spring当中的接口不是一个,所处的包位置不同
            MehodInterceptor interceptor = new MethodInterceptor(){
			@override
            public Object interceptor(Object o, Method method,Object[] args,MethodProxy methodProxy) Throws Throwable{
                 sout."----cglib----log----"//实现额外功能
                     Object ret =method.invoke(userService,args);//执行原始类的方法
                //方法执行的三要素:1.执行对象--->原始对象
                //				 2.执行的方法  3.执行方法的参数
                return ret;
            }        
        }
        Enhancer.SetCallBack(interceptor)//通过实现接口的内部类设置额外功能;
        UserService userServiceProxy = (UserService) Enhancer.create();
        //之后就可以使用代理对象userServiceProxy了
    }
    
}

spring如何创建代理对象

1.aop如何帮我们创建动态代理对象?

2.为何通过id值获得的是代理对象而不是原始对象?

3.具体编码

(1)编写原始对象,并配置bean

(2)实现BeanPostProcessor这个接口,并将实现类配置bean

基于注解的AOP编程

1.基本步骤

区别:通过切面类定义额外功能和切入点

@Aspect
public class MyAspect {
    @Around("execution(* *.*(..))")//表示所有方法
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

        System.out.println("---------aspect----log-------");
        Object ret = joinPoint.proceed();
        return ret;
    }
}

在配置文件当中进行配置

<bean id="userService" class="UserServiceImpl"/>
<bean id="myAspect" class="MyAspect"/>
  <!--  开启aop注解编程,设置底层为cglib将proxy-target-class设置为true-->
    <aop:aspectj-autoproxy proxy-target-class="true"/>

细节:切入点复用

@Aspect
public class MyAspect {
    //切入点的复用,避免对于各种around方法当中的切入点进行多次修改
    //eg.将所有的login要该成register就要2个around函数都修改
    @Pointcut("execution(* *.login(..))")
    public void myPointCut(){}//空的函数体

    @Around("myPointCut()")//直接写自定义的切入点函数名即可
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

        System.out.println("---------aspect1----log-------");
        Object ret = joinPoint.proceed();
        return ret;
    }
    @Around("myPointCut()")
    public Object around2(ProceedingJoinPoint joinPoint) throws Throwable {

        System.out.println("---------aspect2----log-------");
        Object ret = joinPoint.proceed();
        return ret;
    }
}

开发的时候可能存在的问题:

AOP总结

标签:对象,Sping,Object,public,bean,整理,方法,切入点
来源: https://www.cnblogs.com/katy0308/p/13781340.html