spring相关知识点(ioc与aop的实现方式)


在这里插入图片描述

一、ioc-控制反转

1.依赖注入

控制反转是目的,依赖注入是实现方式;实际上是工厂模式+反射机制

interface Fruit {
    public abstract void eat ();
}

class Apple implements Fruit {
    public void eat () {
        System.out.println("Apple");
    }
}

class Orange implements Fruit {
    public void eat () {
        System.out.println("Orange");
    }
}

class Factory {
    public static Fruit getInstance (String ClassName) {
        Fruit f = null;
        try {
            f = (Fruit) Class.forName(ClassName).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return f;
    }
}

class Client {
    public static void main (String[] a) {
        Fruit f = Factory.getInstance("io.github.dunwu.spring.Apple");
        if (f != null) {
            f.eat();
        }
    }
}

2.bean的作用域

类别说明
singleton单例模式,ioc容器中只存在一个对象,默认值
propertype每次调用创建一个对象
request每次http请求创建一个bean,作用于webApplicationContext环境
session同一个http session共用一个bean,不同session使用不同的bean,同样作用与webApplicationContext环境中
globalSession作用与portlet环境,仅适用于webApplicationContext环境中

  比较常用的是singleton和propertype;像singleton,由于共用一个bean,由IOC容器来管理bean的生命周期和状态,不需要反复的创建与销毁,因此性能更高;propertype模式的话,每次请求相当于new了一次实例,一旦创建成功,容器不在跟踪实例,也不会维护Bean实例的状态。
  那么什么时候时候使用singleton什么时候使用propertype呢?正常情况下考虑性能问题都使用默认的singleton,但是在要考虑线程安全问题的时候则使用propertype,比如bean中有非静态变量的时候,就使用propertype;如:

@service
public class test{
	private num = 0;
	
	.........
}

3.bean的生命周期

  首先生成bean的描述,然后通过bean工厂后值处理器,处理bean的相关属性,然后进行bean的初始化,其中BeanPostProcessor前和后的操作,然后bean就ok了,容器关闭,destory方法销毁;如下图:
bean的生命周期

在这里插入图片描述
在这里插入图片描述

二、aop-面向切面编程

  springAOP是通过动态代理模式来实现的;动态代理有两种实现,jdk proxy和cglib;

1.jdk代理模式

   public class JDKDynamicProxy implements InvocationHandler {
 
     //被代理的目标对象
    private Object proxyObj;  
    
    /**
      * Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
      * loader    :类加载器 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
      * interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
       * h         :一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
     */
       public Object newProxy(Object proxyObj){  
             this.proxyObj = proxyObj;
            //返回一个代理对象  
           return Proxy.newProxyInstance(proxyObj.getClass().getClassLoader(),   
                                      proxyObj.getClass().getInterfaces(),   
                                      this);  
       }  
 
      /**
       * 执行目标对象
       * Object  proxy:被代理的对象
       * Method  method:要调用的方法
       * Object  args[]:方法调用时所需要的参数
       */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                                   throws Throwable {       
             before(); 
             Object object = method.invoke(this.proxyObj,args);  // 通过反射机制调用目标对象的方法
             after();       
             return object;  
         }
    
         public void before(){
              System.out.println("开始执行目标对象之前..."); 
         }
    
         public void after(){
             System.out.println("开始执行目标对象之后..."); 
         }
     }

2.cglib代理模式

import java.lang.reflect.Method;
  import net.sf.cglib.proxy.Enhancer;
  import net.sf.cglib.proxy.MethodInterceptor;
  import net.sf.cglib.proxy.MethodProxy;
 
    public class CGLIBProxy implements MethodInterceptor{
 
    private Object targetObject ;//被代理的目标对象
    
    public Object createProxyInstance(Object targetObject) {
 
           this.targetObject = targetObject;
 
           Enhancer enhancer = new Enhancer();
 
           enhancer.setSuperclass(targetObject.getClass());// 设置代理目标
 
           enhancer.setCallback(this);// 设置回调
 
           return enhancer.create();
 
    } 
    
 
    /**
     * 在代理实例上处理方法调用并返回结果 
     * @param object : 代理类
     * @param method :被代理的方法
     * @param args :该方法的参数数组
     * @param methodProxy
     */
    @Override
    public Object intercept(Object object, Method method, Object[] args,
            MethodProxy methodproxy) throws Throwable {        
        Object result = null;    
        try {
              System.out.println("前置处理开始 ...");
              result = methodproxy.invoke( targetObject , args);//执行目标对象的方法
              System.out.println("后置处理开始  ...");
           } catch (Exception e) {
               System.out.println("异常处理 ...");
           } finally {
               System.out.println("调用结束 ...");
           }
           return result; 
       }   
   }

3.两种代理模式对比

1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

注:JDK动态代理要比cglib代理执行速度快,但性能不如cglib好。

三、spring注解

@Cacheable-spring的缓存注解

@Cacheable能干什么?
为了通俗易懂的理解,举个栗子:一个方法,getBooksByUsernameAndLanguage(String username, int language),显然,是一个获取数据库里所有我的英文书对象的方法,返回应该是一个列表。如果这个函数的返回值很大,而且会在页面上被经常调用,那么每一次调用都要重新连接数据库并返回一个数据量庞大的list,可能页面响应和资源占用会比较大。而我们希望的是,第一次调用这个方法时,返回的数据能被放到服务器端的缓存里,以便于后面要调用这个方法时,能直接从缓存里取到,这样就不用再查数据库占用资源了。而@Cacheable的作用就是这个。

@Cacheable(value = "CACHE_BOOK",key = "#username", condition = "#language = 1")
public List<Book> getBooksByUsernameAndLanguage(String username, int language) {
     // balabalabala...里面的代码不重要
     return bookList;
}

看code,@Cacheable注解只有三个属性。

value : 必须要的。就是个自己取的名字,通过它指明了第一次调用这个方法时返回的bookList将被存在内存的哪里。
key : 可选。要使用SpEL表达式,这里与参数username对应,当传入的username值变了的话就不去取缓存里的数据了,而是执行getBooksByUsernameAndLanguage方法。(这是必须的,因为username变了,返回值也就变了,缓存里的数据不符合了,因此这个选项很重要)。spring默认用方法的签名来当做key。
condition:方法返回的结果bookList,要不要缓存起来?condition就添加了一个限定条件。这个例子中,只有传入的语言代码是1,返回的bookList才会被缓存起来,如果给language传了别的值,那么bookList是不会缓存起来的。

注入相关-@Autowired @Resource @Qualifier

1.@Autowired:
@Autowired : 默认是以byType按类型自动注入。
@Autowired + @Qualifier(“名称”):将按照名称自动注入
2.@Resource:
@Resource() 如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称注入,
如果注解写在setter方法上默认取属性名进行注入。
当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
@Resource(name="") 将按照名称自动注入

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值