• Spring学习笔记


    IoC和DI理解

    https://www.w3cschool.cn/wkspring/tydj1ick.html spring在线文档

    IoC(控制反转)

      首先想说说IoC(Inversion of Control,控制反转)。这是spring的核心,贯穿始终。所谓IoC,对于spring框架来说,
    就是由spring来负责控制对象的生命周期和对象间的关系。这是什么意思呢,举个简单的例子,我们是如何找女朋友的?常
    见的情况是,我们到处去看哪里有长得漂亮身材又好的mm,然后打听她们的兴趣爱好、qq号、电话号、ip号、iq号………
    ,想办法认识她们,投其所好送其所要,然后嘿嘿……这个过程是复杂深奥的,我们必须自己设计和面对每个环节。传统的程序
    开发也是如此,在一个对象中,如果要使用另外的对象,就必须得到它(自己new一个,或者从JNDI中查询一个),
    使用完之后还要将对象销毁(比如Connection等),对象始终会和其他的接口或类藕合起来。

      那么IoC是如何做的呢?有点像通过婚介找女朋友,在我和女朋友之间引入了一个第三者:婚姻介绍所。婚介管理了很多男
    男女女的资料,我可以向婚介提出一个列表,告诉它我想找个什么样的女朋友,比如长得像李嘉欣,身材像林熙雷,唱歌像周
    杰伦,速度像卡洛斯,技术像齐达内之类的,然后婚介就会按照我们的要求,提供一个mm,我们只需要去和她谈恋爱、结婚
    就行了。简单明了,如果婚介给我们的人选不符合要求,我们就会抛出异常。整个过程不再由我自己控制,而是有婚介这样一
    个类似容器的机构来控制。Spring所倡导的开发方式就是如此,所有的类都会在spring容器中登记,告诉spring你是个什么东
    西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。
    所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体
    的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。

    DI(依赖注入)

      IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Inje
    ction,依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection
    对象,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,
    A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就
    完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的
    ,依赖注入的名字就这么来的。那么DI是如何实现的呢? Java 1.3之后一个重要特征是反射(reflection),它允许程序
    在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的。

    理解了IoC和DI的概念后,一切都将变得简单明了,剩下的工作只是在spring的框架中堆积木而已。


    装配bean基于xml

    实例化方式

    <bean id="beans1" class="helloImpl"/>
    
    <bean>配置需要创建的对象
    id:用于之后从spring容器获得实例时使用的
    class:需要创建实例的全限定类名
    
     @Test
        public void test1(){
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
            helloImpl beans1 = (helloImpl) context.getBean("beans1");
            beans1.say();
        }
      
    

    BeanFactor: 这是一个工厂,用于生成任意bean,采取延迟加载,第一次getBean时才会初始化Bean

    ApplicationContext:是BeanFactor的子接口,功能更强大(国际化处理,事件传递,bean自动装配,各种不同应用层的context
    实现)。当配置文件被加载,就进行对象实例化

    ClassPathXmlApplicationContext:用于加载classpath(类路径,src)下的xml
    加载xml运行位置-》WEB-INF/class/。。。xml

    FileSystemXmlApplicationContext:用于加载指定盘符下的xml
    加载xml运行位置-》WEB-INF/。。。xml
    通过javaweb ServletContext getRealPath()获得具体盘符

    静态工厂创建的实例交予spring
    class:确定静态工厂全限定类名
    factory-method:确定静态方法

    工厂:
    public class mybeanfactory{
    	public static userservice createservice(){
    		return new userserviceimpl();
    	}
    }
    
    
    spring配置
    	将静态工厂创建的实例交予spring
    		class确定静态工厂全限定类名
    		factory-method 确定静态方法名
    
        
     静态工厂(方法静态),测试的时候  不需要new工厂  可以直接工厂.方法
    	userservice s=mybeanfactory.createservice();
    	s.adduser();
     配置静态工厂的spring xml
    	<bean id=""  class="(工厂的全限定类名)" factory-method="(方法名(可能有很多就写清楚具体方法))"</bean>
     
     实例工厂:需要new
     	mybeanfactory  f= new mybeanfactory();
    	userservice s=f.createservice();
    	s.adduser();
    
     配置实例工厂的spring xml
    	1.创建工厂实例
    		<bean id="a"  class=""/>
    	2.获取userservice  factory-bean 确定工厂实例  factory-method 确定普通方法
    		<bean id=""  factory-bean="a"  factory-method="(工厂中具体的方法名)" />
    	          
    

    bean的种类

    普通bean:之前操作的都是普通bean。 <bean id="" class="A"/>, spring直接创建A的实例并返回
    
    FactoryBean:是一个特殊的bean,具有工厂生成对象的能力,只能生成特定的对象
    	bean必须实现FactoryBean接口,此接口提供方法, getOeject() 用于获得特定的bean
    	<bean id="" class="FB"/>先创建FB实例,使用调用getObject()方法,并返回方法的返回值
    	==》FB fb=new FB();
    		return fb.getObject();
    
    BeanFactory和FactoryBean对比
    	BeanFactory:工厂,用于生成任意bean。
    	FactoryBean:特殊bean用于生成另一个特定的bean,例如:ProxyFactoryBean,此工厂bean用于生产代理。
    				<bean id="" class="...ProxyFactoryBean" />获得代理对象实例,AOP使用
    
    

    作用域

    作用域:用于确定spring创建bean实例个数
            当在 Spring 中定义一个 bean 时,你必须声明该 bean 的作用域的选项。例如,为了强制 Spring 在每次需要时都产生一个新的 
            bean 实例,你应该声明 bean 的作用域的属性为 prototype。同理,如果你想让 Spring 在每次需要时都返回同一个bean实例,
            你应该声明 bean 的作用域的属性为 singleton。
            
    	scope配置项有5个属性,用于描述不同的作用域。  
    		<bean id="" class="...impl" scope=" " />
    
    		① singleton(单例,默认值)
    
    			在spring ioc容器中仅存在一个bean实例,bean以单例方式存在,默认值
    
    		② prototype(多例)
    
    			每次从容器中调用bean时,都返回一个新的实例,即每次调用getbean()时,相当于执行new xxxbean()
    
    		③ request
    
    			该属性仅对HTTP请求产生作用,使用该属性定义Bean时,每次HTTP请求都会创建一个新的Bean,适用于WebApplicationContext环境。
    
    		④ session
    
    			该属性仅用于HTTP Session,同一个Session共享一个Bean实例。不同Session使用不同的实例。
    
    		⑤ global-session
    
    			该属性仅用于HTTP Session,同session作用域不同的是,所有的Session共享一个Bean实例。
    
    
    
    

    生命周期

    初始化和销毁
    
        目标方法执行前、执行后,将进行初始化或销毁
            要求:1.容器必须close,销毁方法才能执行
                2.必须单例
                        1. ApplicationContext applicationContext = new ClassPathXmlApplicatonContext(xmlpath)
                            applicationContext.getClass().getMethod("close").invoke(applicationContext)
                            //ApplicationContext是接口  接口中没有定义,实现类提供 反射执行实现类
    
                        2. ClassPathXmlApplicatonContext applicationContext = new ClassPathXmlApplicatonContext(xmlpath)
                            applicationContext.close();
    
            <bean id="" class="" init-method="初始化方法名称" destroy-method="销毁的方法名称"/>
    
    
    BeanPostProcessor后处理Bean
        spring提供一种机制,只要实现此接口BeanPostProcessor,并将实现类提供给spring容器,spring容器将自动执行
        。在初始化方法前执行before(),在初始化方法后执行after()
                
        spring提供工厂钩子,用于修改实例对象,可以生成代理对象,时aop底层
                A a = new A();
                a=B.before(a);    ----->将a的实例对象传递给后处理bean,可以生成代理对象并返回
                a.init();
                B.after(a);
                a.addUser();
                a.destroy();
    

    属性依赖注入

    setter注入
    <bean id="personid" class="">
        <property name="pname" value="XXX"></property>
        <property name="age" >
            <value>1234</value>
        </property>
        
        <property name="homeaddr" ref="aaa"></property>
    
    <bean id="aaa" class="">
    	<property name="addr" value="XXX"></property>
    </bean>
    
    
    
    P命名空间(了解)
    
        对“setter方法注入”进行简化,替换<property name="属性名">,而是在
        <bean p:属性名="普通值" p:属性名-ref="引用值">
    
        p命名空间使用前提,必须添加命名空间
        引用约束:xmlns:p="..../schema/p"
    
    例:<bean id="" class="" p:name="" p:age="" p:homeaddr-ref=""/>
    
    
    
    
    
    SpEL(了解)
    
    对<property>进行统一编程,所有的内容都使用value
    <property name="" value="#{表达式}">
    #{123}、#{'jack'} : 数字、字符串
    #{beanId} : 另一个bean引用
    #{beanId.propName} : 操作数据
    #{beanId.toString} : 执行方法
    #{T(类).字段|方法}   : 静态方法或字段
    
    
    
    
    集合
    
    集合的注入都是给<property>添加子标签
            数组: <array>
            List: <List>
            Set: <set>
            Map: <map>
            propertis: <props>
    普通数据:<value>
    引用数据:<ref>
    
    例子:
    <bean id="" class="">
        <property name="bean的属性">
            <array> (<list> <set>同理)
                <value>aaa</value>
                <value>bbb</value>
                <value>ccc</value>
            </array>
        </property>
        
        <property name="bean的属性">
            <map> 
                <entry key="" value=""></entry>
            </map>
        </property>
        
        <property name="bean的属性">
            <props> 
                <prop key="XXX" >XXX</prop>
            </props>
        </property>
    

    装配bean基于注解

    注解:就是一个类,取代@注解名称
    开发中:使用注解,取代xml配置文件
    
    需要引入dtd(命名空间的声明)
    -------------------------------------------------------------
                <?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">
                    <!-- 组件扫描,扫描含有注解的类 -->
                    <context:component-scan base-package="test"></context:component-scan>
                </beans>
    --------------------------------------------------------------
    
    
    1.@component 取代 <bean class="">
    	@component("id") 取代 <bean id="" class="">
    
    2.web开发,提供3个@component注解衍生注解(功能一样)
            @Repository:dao层
            @Service:service层
            @Controller:web层
     使用前先扫描包
            
    3.依赖注入	给私有字段设置,也可以给setter方法设置
        普通值 @Value("")
        引用值
            方式1:按照【类型】注入
            	@Autowrired
            方式2:按照【名称】注入1
            	@Autowrired
           		@Qualifier("名称")
            方式3:按照【名称】注入2
                @Resource("名称")
                
                
                
    @Required 
                注释应用于 bean 属性的 setter 方法,它表明受影响的 bean 属性在配置时必须放在 XML 配置文件中
    			,否则容器就会抛出一个 BeanInitializationException 异常。下面显示的是一个使用 @Required 注释的示例。
    @Qualifier
                可能会有这样一种情况,当你创建多个具有相同类型的 bean 时,并且想要用一个属性只为它们其中的一个进行装配,在这种
                情况下,你可以使用 @Qualifier 注释和 @Autowired 注释通过指定哪一个真正的 bean 将会被装配来消除混乱。
    
    
    

    AOP

    aop术语
        1.target:目标类,需要被代理的类,例如:UserService
        2.joinpoint:连接点,所谓连接点时值那些可能被拦截到的方法,例如:所有方法
        3.poincut:切入点,已经被加强的连接点,例如:add user()
        4.advice:通知/增强,增强代码。例如:after、before
        5.weaving:织入,指把增强advice应用到目标对象target来创建新的代理对象的过程
        6.proxy:代理类
        7.aspect:切面,是切入点pointcut和通知advice的结合
            一个线时一个特殊的面
            一个切入点和一个通知,组成一个特殊的面
    
    

    AOP


    手动代理

    public static Userservice createservice(){
        //1.目标类
        Userservice userservice = new UserserviceImpl();
        
        //2.切面类
        MyAspect myaspect = new MyAspect();
        
        /* 3.代理类:将目标类(切入点)和切面类(通知)结合--》切面
        proxy.newProxyInstance
        参数1.loader,类加载器,动态代理类运行时创建,任何类都需要类加载器将其加载到内存
                一般情况:当前类:class.getClassLoader();
                		目标类实例:getClass().get...
        参数2.class[] interfaces 代理类需要实现的所有接口
                 方式1.目标类实例:getClass().getInterfaces();    注意:只能获得自己的接口,不能获得父类元素的接口
                 方式2.new Class[]{UserService.class}
                 例如:jdbc驱动--》DriverManager   获得接口Connection
         
        参数3.InvocationHandler  处理类,接口,必须进行实现类,一般采用匿名内部类
            提供invoke方法,代理类的每一个方法执行时,都将调用一次invoke
            参数31:Object proxy:代理对象
            参数32:Method method:代理对象当前执行的方法的描述对象(反射)
            参数33:Object[] args:方法实际参数
         */
        
    }
    
    

    手动代理例子

    UserService

    package com.yjf.JDk;
    
    public interface UserService {
    	public void add();
    	public void delete();
    	public void find();
    }
    
    

    Myaspect

    package com.yjf.JDk;
    
    public class Myaspect {
    	public void after() {
    		System.out.println("------after");
    	}
    	public void before() {
    		System.out.println("------befor");
    	}
    }
    
    

    MybeanFactory

    package com.yjf.JDk;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class MybeanFactory {
    	public static UserService creatservice() {
    		 UserService userService=new UserServiceImpl();
    		
    		 Myaspect myaspect = new Myaspect();
    		
    		UserService proxyService=(UserService) Proxy.newProxyInstance(
    				MybeanFactory.class.getClassLoader(),
    				userService.getClass().getInterfaces(),
    				new InvocationHandler() {
    					
    					@Override
    					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    						// TODO Auto-generated method stub
    						myaspect.after();
    						Object object=method.invoke(userService);
    						myaspect.before();
    						return object;
    					}
    				}
    				);
    		return proxyService;
    	}
    }
    
    

    test

    package com.yjf.JDk;
    
    public class test {
    public static void main(String[] args) {
    	UserService u=MybeanFactory.creatservice();
    	u.add();
    	u.delete();
    	u.find();
    }
    }
    
    

    结果

    ------after
    add---------
    ------befor
    ------after
    delete---------
    ------befor
    ------after
    find---------
    ------befor
    
    
  • 相关阅读:
    React Native-安卓环境的搭建
    python爬虫学习之日志记录模块
    Python爬虫学习之正则表达式爬取个人博客
    eclipse运行spark程序时日志颜色为黑色的解决办法
    python爬虫学习之爬取全国各省市县级城市邮政编码
    python 字典详细使用
    python爬虫学习之查询IP地址对应的归属地
    python jieba库的基本使用
    Eclipse环境搭建并且运行wordcount程序
    Hadoop2.0伪分布式平台环境搭建
  • 原文地址:https://www.cnblogs.com/sm1128/p/10939582.html
Copyright © 2020-2023  润新知