本文共 6416 字,大约阅读时间需要 21 分钟。
本教程对应视频课程:
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标签的解析程序<context:annotation-config />
6、@Autowired找bean的方式:
①首先按照依赖对象的类型找;如果找到,就是用setter或者字段直接注入
②如果在Spring上下文中找到多个匹配的类型,再按照名字去找;如果没有匹配,报错
③可以通过使用@Qualifier("other")标签来规定依赖对象按照bean的id+类型去找
@Resource标签:
1.Resource标签是JavaEE规范的标签、
2、Resource标签也可以作用于字段或者setter方法
3、也可以使用@Resource标签注入一些spring内置的重要对象,比如BeanFactory.ApplicationContext
4、Resource必须要求有匹配的对象
5、Resource标签找bean的方式
①首先按照名字去找,如果找到,就使用setter或者字段注入
②如果按照名字找不到,再按照类型去找,但如果找到多个匹配类型则会报错
③可以直接使用name属性指定bean的名称;但是,如果指定的name,就只能按照name去找,如果找不到,就不会再按照类型去找;
1、使用标签来完成IoC,就必须有IoC标签的解析器
使用context:component-scan来扫描spring需要管理的bean
base-package就告诉spring去哪些包及其子包里去扫描bean,如果有多个包需要被扫描;只需要用逗号隔开多个包即可
<context:component-scan base-package="cn.org.kingdom.service,cn.org.kingdom.dao" />
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() {}
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、代理对象完全包含真实对象,客户端使用的都是代理对象上面的方法,和真实对象无关;
2、静态代理能够处理把不是真实对象该做的事情从真实对象上面撇开;
3、静态代理带来的问题:需要为每一个真实对象都得创建一个代理对象,导致类会急剧增加
/** 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方法中对要执行的方法名进行判断
若一个类,没有接口如何代理 ?
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库生成目标对象的子类。对接口创建代理优于对类创建代理,因为会产生更加松耦合的系统。
转载于:https://blog.51cto.com/11230344/2287873