本教程对应视频课程:http://edu.51cto.com/course/14731.html

1、自动装配

1.1、Spring标签

Autowired标签的作用

1、通过autowired标签可以让spring自动的把属性需要的对象从容器中找出来,并注入到对象

2、autowired标签可以放在字段或者setter方法上面

3、使用autowired标签可以注入一些spring内置的重要对象,比如BeanFactory,ApplicationContext;

4、默认情况下,@Autowired标签必须要能找到对应的对象,否则报错;通过required=false来避免这个问题@Autowired(required=false)

5、第三方程序:spring3.0之前,需要手动配置@Autowired解析程序:spring就会自动的加入针对@Autowired标签的解析程序

6、@Autowired找bean的方式:

​ ①首先按照依赖对象的类型找;如果找到,就是用setter或者字段直接注入

​ ②如果在Spring上下文中找到多个匹配的类型,再按照名字去找;如果没有匹配,报错

​ ③可以通过使用@Qualifier("other")标签来规定依赖对象按照bean的id+类型去找

1.2、J2EE标签

@Resource标签:

1.Resource标签是JavaEE规范的标签、

2、Resource标签也可以作用于字段或者setter方法

3、也可以使用@Resource标签注入一些spring内置的重要对象,比如BeanFactory.ApplicationContext

4、Resource必须要求有匹配的对象

5、Resource标签找bean的方式

​ ①首先按照名字去找,如果找到,就使用setter或者字段注入

​ ②如果按照名字找不到,再按照类型去找,但如果找到多个匹配类型则会报错

​ ③可以直接使用name属性指定bean的名称;但是,如果指定的name,就只能按照name去找,如果找不到,就不会再按照类型去找;

1.3、使用注解来化解配置

1、使用标签来完成IoC,就必须有IoC标签的解析器

​ 使用context:component-scan来扫描spring需要管理的bean

​ base-package就告诉spring去哪些包及其子包里去扫描bean,如果有多个包需要被扫描;只需要用逗号隔开多个包即可

2、标注Bean的注解:@Component

默认情况,直接使用类的名字(首字母小写作为bean的名字), 如果要修改bean的名称;直接使用value属性来重新定义bean的名称

@Component("otherbean")

public class OtherBean {}

3、使用@Component的限制:

①不能运用到静态工厂方法和实例工厂方法,但是可以使用到FactoryBean;

②对于没有源代码的类(框架内部的预定义类),只能用XML配置;

4、bean组件分类

@Service用于标注业务层组件

@Controller用于标注控制层组件(如struts中的action)

@Repository用于标注数据访问组件,即DAO组件

@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。

5、指定bean的作用域:@Scope("prototype")

6、初始化和销毁方法

@PostConstruct

public void init() {}

@PreDestroy

public void destory() {}

1、动态代理

1.1、静态代理回顾

1.1.1、模型图

1.1.2、代码实现

package cn.org.kingdom.proxy;
interface Subject{
    public void getMoney();
}
class RealSubject implements Subject{
    @Override
    public void getMoney() {
        System.out.println("求求你,能不能还我钱");
    }
}
class Proxy implements Subject{
    private Subject subject;
    public Subject getSubject() {
        return subject;
    }
    public void setSubject(Subject subject) {
        this.subject = subject;
    }
    public void preGetMoney(){
        System.out.println("带上大砍刀");
    }
    @Override
    public void getMoney() {
        preGetMoney();
        subject.getMoney();
        afterGetMoney();
    }
    public void afterGetMoney(){
        System.out.println("赔偿精神损失费,拿去佣金");
    }
}
public class ProxyTest {
    public static void main(String[] args) {
        RealSubject real = new RealSubject() ; 
        Proxy p = new Proxy();
        p.setSubject(real);
        p.getMoney();
    }
}

1.1.3、静态代理

1、代理对象完全包含真实对象,客户端使用的都是代理对象上面的方法,和真实对象无关;

2、静态代理能够处理把不是真实对象该做的事情从真实对象上面撇开;

3、静态代理带来的问题:需要为每一个真实对象都得创建一个代理对象,导致类会急剧增加

1.2、动态代理

1.2.1、jdk的动态代理

/**
    ClassLoader loader:类加载器
    Class[] interfaces:要实现的接口
    InvocationHandler h:调用处理器
    return :代理对象
*/
public static Object newProxyInstance(ClassLoader loader, Class[] interfaces,InvocationHandler h){}
/**
    proxy:生成的代理对象
    method:当前调用的真实方法
    args: 当前调用方法的实参
    return : 真实方法的返回结果
*/
public Object invoke(Object proxy, Method method, Object[] args) {}    

参考代码

package cn.org.kingdom.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import cn.org.kingdom.ts.Transation;
public class MyinvocationHanlder implements InvocationHandler {
    //真实角色
    private Object obj ;  //obj必须实现接口(jdk原生动态代理)
    //ts附加功能对象
    private Transation ts ; 
    public MyinvocationHanlder() {
        super();
    }
    public MyinvocationHanlder(Object obj, Transation ts) {
        super();
        this.obj = obj;
        this.ts = ts;
    }
    public Object getObj() {
        return obj;
    }
    public void setObj(Object obj) {
        this.obj = obj;
    }
    public Transation getTs() {
        return ts;
    }
    public void setTs(Transation ts) {
        this.ts = ts;
    }
    public Object getProxy(){
        return 
                Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        Object value = null ; 
        if(obj.getClass().getName().endsWith("ServiceImpl")){
            if("add".equals(method.getName())||"insert".equals(method.getName())) {
                //aop要植入的操作
                try{
                    ts.begin();
                    value= method.invoke(obj, args);
                    int c= 10/0;
                    ts.commit();
                }catch(Exception e)  {
                    ts.rollback();
                }
                return value;
            }else{
                method.invoke(obj, args);
            }
        }   
        return null;
    }
}

JDK动态代理

①代理的对象必须要实现一个接口;

②需要为每个对象创建代理对象;

③动态代理的最小单位是类(所有类中的方法都会被处理);

JDK动态代理总结

①JAVA动态代理是使用java.lang.reflect包中的Proxy类与InvocationHandler接口这两个来完成的。

②要使用JDK动态代理,必须要定义接口。

③JDK动态代理将会拦截所有pubic的方法(因为只能调用接口中定义的方法),这样即使在接口中增加了新的方法,不用修改代码也会被拦截。

④如果只想拦截一部分方法,可以在invoke方法中对要执行的方法名进行判断

1.2.2、CGLIB动态代理

若一个类,没有接口如何代理 ?

javassist.jar:Struts2的代理实现方案.

cglib.jar:Spring的代理实现方案

java类实现

public class TransactionCallback implements org.springframework.cglib.proxy.InvocationHandler {
    private Object target;//真实对象
    private TransactionManager txManager;
    //不需要事务的方法
    private String[] methodNames = { "update", "get" };
    public TransactionCallback(Object target, TransactionManager txManager) {
        this.target = target;
        this.txManager = txManager;
    }
    //创建代理对象
    public Object getProxyInstance() {
        Enhancer enhancer = new Enhancer();
        enhancer.setClassLoader(this.getClass().getClassLoader());
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
    public Object invoke(Object proxy, Method method, Object[] args){
        Object ret = null;
        if(Arrays.asList(methodNames).contains(method.getName())){
            method.invoke(target, args);
            return null;
        }
        txManager.beginTransaction();
        try {
            method.invoke(target, args);
            txManager.commint();
        } catch (Exception e) {
            txManager.rollback();
        }
        return ret;
    }
}

总结:

CGLIB代理总结:

①CGLIB可以生成目标类的子类,并重写父类非final修饰符的方法。

②要求类不能是final的,要拦截的方法要是非final、非static、非private的。

③动态代理的最小单位是类(所有类中的方法都会被处理);

代理总结:

Spring中:

1、若目标对象实现了若干接口,spring就会使用JDK动态代理。

2、若目标对象没有实现任何接口,spring就使用CGLIB库生成目标对象的子类。对接口创建代理优于对类创建代理,因为会产生更加松耦合的系统。