Spring学习笔记2

一、自动装配(xml方式、不推荐)

1.一般方式

<bean id="otherBean" class="spring_autowired_xml.OtherBean" />
   <bean id="someBean" class="spring_autowired_xml.SomeBean">
        <property name="otherBean" ref="otherBean" />
   </bean>

2.自动装配

<bean autowire="" />
        -default    :不自动注入
        -no         :不自动注入
        -byName     :按照名字注入(按照属性的名字在spring中找bean)
        -byType     :按照依赖对象的类型注入
        -constructor:按照对象的构造器上面的参数类型注入
        注意:
            1,如果按照byName自动注入,要求所有的属性名字和id的名字必须保证一种规范的命名方式;
            2,如果按照byType注入,如果spring中同一个类型有多个实例----报bean不是唯一类型错误;
 <bean id="otherBean" class="spring_autowired_xml.OtherBean" />
   <bean id="someBean" class="spring_autowired_xml.SomeBean" autowire="byType" />
   <bean id="otherBean" class="spring_autowired_xml.OtherBean" />
   <bean id="someBean" class="spring_autowired_xml.SomeBean" autowire="byName" />

二、自动装配(注解方式)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
            http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans.xsd
            ">

   <bean id="otherBean" class="spring_autowired_ann.OtherBean" />
   <bean id="otherBean2" class="spring_autowired_ann.OtherBean2" />

   <bean id="someBean" class="spring_autowired_ann.SomeBean"/>
</beans>
public class SomeBean {
    //@Autowired
    private OtherBean otherBean;
    //@Autowired
    private OtherBean2 otherBean2;
    @Autowired
    public void setXXX(OtherBean otherBean,OtherBean2 otherBean2){
        this.otherBean = otherBean;
        this.otherBean2 = otherBean2;
    }
    @Override
    public String toString() {
        return "SomeBean [otherBean=" + otherBean + ", otherBean2="
                + otherBean2 + "]";
    }   

}

1,@Autowired标签:

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

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

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

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

5,@Autowired找bean的方式:
1),首先按照依赖对象的类型找;如果找到,就是用setter或者字段直接注入;
2),如果在Spring上下文中找到多个匹配的类型,再按照名字去找;如果没有匹配,报错;
3),可以通过使用@Qualifier(“otherBean”)标签来规定依赖对象按照bean的id+类型去找;

2,@Resource标签:

1,@Resource标签是JavaEE规范的标签;
2,@Resource标签也可以作用于字段或者setter方法;
3,也可以使用@Resource标签注入一些spring内置的重要对象,比如BeanFactory.ApplicationContext;
4,@Resource必须要求有匹配的对象;
5,<context:annotation-config>既引入了@Autowired标签的解析器,也引入了@Resource的解析器;
6,@Resource标签找bean的方式:
1),首先按照名字去找,如果找到,就使用setter或者字段注入;
2),如果按照名字找不到,再按照类型去找,但如果找到多个匹配类型,报错;
3),可以直接使用name属性指定bean的名称;但是,如果指定的name,就只能按照name去找,如果找不到,就不会再按照类型去找;

3,@Autowired标签和@Resource标签如何择选

1.@AutowiredSpring的标签,使用,和Spring耦合,有可能有未知的错误.---Spring
2,@Resouce:J2EE的规范,所以稳定,在J2EE规范容器中也能正常使用;

三、使用注解简化IoC

<?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
            ">              
     <!-- 
        @Component:把该对象交给Spring进行管理
        扫描哪些包及其子包中@Component注解
        若要扫描多个包,用逗号分隔,也可以定义多个<context:component-scan base-package=""/>
      -->
    <context:annotation-config />
    <context:component-scan base-package="spring_ann_IoC" />
</beans>
package spring_ann_IoC;

import org.springframework.stereotype.Component;
@Component
public class OtherBean {

}
package spring_ann_IoC;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
public class SomeBean {
    @Autowired
    @Qualifier("otherBean")
    //@Qualifier("sb")
    private OtherBean otherBean;

    @Override
    public String toString() {
        return "SomeBean [otherBean=" + otherBean + "]";
    }   

}

1.标注Bean的注解:@Component

默认情况,直接使用类的名字(首字母小写作为bean的名字)

如果要修改bean的名称;直接使用value属性来重新定义bean的名称

OtherBean类
package spring_ann_IoC;

import org.springframework.stereotype.Component;
@Component("sb")
public class OtherBean {

}
SomeBean类
@Component
public class SomeBean {
    @Autowired
    //@Qualifier("otherBean")
    @Qualifier("sb")
    private OtherBean otherBean;

    @Override
    public String toString() {
        return "SomeBean [otherBean=" + otherBean + "]";
    }   

}

2.使用@Component的限制:

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

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

3.是否是单例的

在我们自己用xml配置bean的时候我们可以设置Scope对于注解方式如何实现?

注解方式默认也是单例的。

我们只需要设置@Scope(“prototype”)

@Component
@Scope("prototype")
public class SomeBean {
    @Autowired
    //@Qualifier("otherBean")
    @Qualifier("sb")
    private OtherBean otherBean;

    @Override
    public String toString() {
        return "SomeBean [otherBean=" + otherBean + "]";
    }   

}

3.初始化和销毁

@PostConstruct
public void init(){
    System.out.println("init()...........");
}
@PreDestroy
public void destroy(){
    System.out.println("destroy........");
}

4.bean组件版型标签

bean组件版型:

@Service用于标注业务层组件、

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

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

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

bean组件版型用法和@Component一样,仅仅是名字不同,用的地方不同。

三、代理

1.静态代理

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

2,静态代理能够处理:

1),把不是真实对象该做的事情从真实对象上面撇开;

3,静态代理带来的问题:

1),还是需要在每一个方法上面处理额外的业务;业务代码(大家都需要做的事情,公共的事情)还是分散在各个方法中的;

2),需要为每一个真实对象都得创建一个代理对象

public interface Rent {

    public void rent();
}
Host
public class Host implements Rent {

    @Override
    public void rent() {
        System.out.println("出租房屋。。。。。。");
    }

}
Proxy
public class Proxy implements Rent{

    private Host host;

    @Override
    public void rent() {
        seeHouse();
        host.rent();
        fee();
    }

    public void seeHouse(){
        System.out.println("看房。。。。");
    }

    public void fee(){
        System.out.println("收费.....");
    }


    public void setHost(Host host) {
        this.host = host;
    }
}
配置文件
<?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
            ">              
   <bean id="host" class="cn.bdqn.staticproxy01.Host"></bean>
   <bean id="proxy" class="cn.bdqn.staticproxy01.Proxy">
        <property name="host" ref="host"></property>
   </bean>
</beans>
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class TestStaticProxy {
    @Autowired
    private ApplicationContext ac;

    @Test
    public void testAnnIoC(){
        Proxy proxy = ac.getBean("proxy",Proxy.class);
        proxy.rent();
    }
}

2.动态代理(JDK)

JDK动态代理:
1,我代理的对象必须要实现一个接口;
2,需要为每个对象创建代理对象;
3,动态代理的最小单位是类(所有类中的方法都会被处理);

public interface Rent {

    public void rent();
}

Host
public class Host implements Rent {

    @Override
    public void rent() {
        System.out.println("出租房屋。。。。。。");
    }

}
动态代理类
public class PynamicProxy implements InvocationHandler{

    private Object target;  //真是目标对象

    //创建代理对象
    public Object createProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }

    //执行增强操作
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        seeHouse();
        Object result = method.invoke(target, args);
        fee();
        return result;
    }
    public void seeHouse(){
        System.out.println("看房。。。。。。");
    }
    public void fee(){
        System.out.println("收费。。。。。。");
    }
    public void setTarget(Object target) {
        this.target = target;
    }
}
配置文件
<?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
            ">              
   <bean id="host" class="cn.bdqn.dynamicproxy.jdk01.Host"></bean>
   <bean id="proxy" class="cn.bdqn.dynamicproxy.jdk01.PynamicProxy">
        <property name="target" ref="host"></property>
   </bean>
</beans>
测试
public class TestPynamicProxy {
    @Autowired
    @Qualifier("proxy")
    private PynamicProxy proxy;

    @Test
    public void testPynamicProxy(){
        Rent p= (Rent)proxy.createProxy();
        p.rent();
    }
}

JDK动态代理总结:
1,JAVA动态代理是使用java.lang.reflect包中的Proxy类与InvocationHandler接口这两个来完成的。
2,要使用JDK动态代理,必须要定义接口。
3,JDK动态代理将会拦截所有pubic的方法(因为只能调用接口中定义的方法),这样即使在接口中增加了新的方法,不用修改代码也会被拦截。
4,如果只想拦截一部分方法,可以在invoke方法中对要执行的方法名进行判断。

2.动态代理(CGLib)

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

javassist.jar:Hibernate和Struts2的代理实现方案.
cglib.jar:Spring的代理实现方案:

实现类
public class EmployeeServiceImpl{

    public void save() {
        System.out.println("------保存员工------");
    }

}
事务管理类
/**
 * 事务管理器
 * @author Administrator
 *
 */
public class TransactionManager {
    public void beginTransaction(){
        System.out.println("开启事务。。。。");
    }
    public void commit(){
        System.out.println("提交事务。。。。");
    }
    public void rollback(){
        System.out.println("回滚事务。。。。"); 
    }
}
代理类
public class ProxyCallBack implements org.springframework.cglib.proxy.InvocationHandler {
    private Object target;   //真实对象
    private TransactionManager txManager;
    //创建代理对象
    public Object createProxy(){
        //增强器
        Enhancer enhancer = new Enhancer();
        //把真实对象作为代理父类
        enhancer.setSuperclass(target.getClass());
        //设置增强的操作
        enhancer.setCallback(this);
        //创建代理对象
        return enhancer.create();
    }

    //执行增强操作
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        Object obj = null;
        txManager.beginTransaction();
        try {
            obj= method.invoke(target, args);
            txManager.commit();
        } catch (Exception e) {
            txManager.rollback();
        }

        return obj;
    }

    public void setTarget(Object target) {
        this.target = target;
    }

    public void setTxManager(TransactionManager txManager) {
        this.txManager = txManager;
    }


}
测试
@Autowired
private ProxyCallBack proxy;
@Test
    public void testStaticProxy(){
        EmployeeServiceImpl p = (EmployeeServiceImpl)proxy.createProxy();
    p.save();
}
CGLIB代理总结:

1,CGLIB可以生成目标类的子类,并重写父类非final修饰符的方法。
2,要求类不能是final的,要拦截的方法要是非final、非static、非private的。
3,动态代理的最小单位是类(所有类中的方法都会被处理);

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

2,若目标对象没有实现任何接口,spring就使用CGLIB库生成目标对象的子类。

四、AOP

1.1. AOP—Aspect Oriented Programming

面向切面编程——弥补面向对象编程(OOP)的不足
AOP和IOC是Spring的两个核心。AOP是对IOC的补充,他们之间不存在依赖关系。

2. AOP的作用

提供显式的事物管理
允许用户自定义切面

3. AOP的优点

通过静态代理可以使业务类更加纯粹
公共业务由代理完成—实现分工
公共业务高度集中便于扩展和修改

4. 名词

1.关注点:除正常业务以外需要重点注意的事项。如:日志、同步等业务。

2.连接点(Joinpoint):特定方法的调用就可以称为连接点

3.切入点:Pointcut:在哪些类,哪些方法上面切(where);

4.通知/增强Advice:在方法的什么时机(when:方法前/方法后/方法前后)做什么(what:增强的功能);连接点上特定方法执行的动作就称为通知

通知可以分为前置通知(Before advice)、后置通知(After returning advice)、环绕通知(Around Advice)、异常通知(After throwing advice)、最终通知(After (finally) advice)

5.切面(Aspect):一个关注点的模块化就称为切面。也就是切入点+通知: 什么时机,什么地点,干啥!

6.,织入Weaving:把切面加入到对象,并创建出代理对象的过程.(Spring来做的)

5.AOP的配置(xml)

1,依赖的jar包

spring-aop-4.3.3.RELEASE.jar
aopalliance.jar
aspectjweaver.jar

2,引入aop命名空间
3,aop配置

什么时机:什么地点,做什么

<aop:config>
<aop:aspect ref="txManager">:做什么
    <aop:pointcut expression="execution(* cn.itcast.cd.day2._6aop_xml.*Service.*(..))" id="txPoint"/>:什么地点(哪些方法上)
            <aop:before method="beginTransaction" pointcut-ref="txPoint"/>:时机:方法前/方法后/方法前后
4,aspectJ
AOP思想广泛应用于java,专门有一个组织负责aop的一切事物(AOP联盟)
首先就要解决一个问题,怎么表示在那些方法上切。---->aspectJ(语言)
通过表达式语言在那些包下那些类中的那些方法上切(增强)

这里写图片描述

5,实现
接口
public interface IEmployeeService {
    public void save();
}
实现
public class EmployeeServiceImpl implements IEmployeeService {

    @Override
    public void save() {
        System.out.println("------保存员工------");
        throw new RuntimeException("出现异常");
    }

}
事务管理类
/**
 * 事务管理器
 * @author Administrator
 *
 */
public class TransactionManager {
    //在业务方法被调用前,如何获取业务方法的信息
    public void beginTransaction(JoinPoint jp){
        System.out.println("开启事务。。。。");
        //void cn.bdqn.aop_xml.IEmployeeService.save()
        //System.out.println(jp.getSignature());  //得到方法的签名
        //System.out.println(jp.getTarget());     //真是主题对象
        //System.out.println(jp.getArgs());       //方法参数
    }
    public void commit(){
        System.out.println("提交事务。。。。");
    }
    public void rollback(Throwable ex){
        System.out.println("回滚事务。。。。");
        System.out.println(ex.getMessage());
    }
    public void close(){
        System.out.println("关闭Session。。。。");
    }
    /*//环绕业务方法的增强
    //如何调用真正的业务方法
    public void around(){
        System.out.println("开启事务");
        try {
            System.out.println("执行业务方法。。");
            System.out.println("提交事务");
        } catch (Exception e) {
            System.out.println("回滚事务");
        }finally{
            System.out.println("关闭Session");
        }
    }*/
    //调用真正的业务方法,真正的业务方法可能有返回值
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("开启事务");
        try {
            Object result = pjp.proceed();   //调用业务方法
            System.out.println("提交事务");
            return result;
        } catch (Exception e) {
            System.out.println("回滚事务");
        }finally{
            System.out.println("关闭Session");
        }
        return null;
    }
}
<?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"
    xmlns:aop="http://www.springframework.org/schema/aop"
    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
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd
            ">              
    <!-- 
        AOP思想广泛应用于java,专门有一个组织负责aop的一切事物(AOP联盟)
        首先就要解决一个问题,怎么表示在那些方法上切。   aspectJ(语言)
        通过表达式语言在那些包下那些类中的那些方法上切(增强)
     -->
<bean id="txManager" class="cn.bdqn.aop_xml.TransactionManager" />
    <bean id="employeeService" class="cn.bdqn.aop_xml.EmployeeServiceImpl" />
    <aop:config>
        <aop:aspect ref="txManager">
            <aop:pointcut expression="execution(* cn.bdqn.aop_xml.*Service.*(..))" id="txManagerPoint"/>
            <!-- 前置通知:在业务方法执行之前执行增强操作(增强类中的指定增强方法) -->
            <aop:before method="beginTransaction" pointcut-ref="txManagerPoint"/>
            <!-- 后置通知:在业务方法成功调用之后增强操作  
            <aop:after-returning method="commit" pointcut-ref="txManagerPoint"/>-->
            <!-- 
                异常通知:在业务方法中出现异常,需要调用增强操作  
                throwing="ex":决定方法定义为:public void rollback(Throwable ex)

            <aop:after-throwing method="rollback" pointcut-ref="txManagerPoint"
                throwing="ex"
            />-->
            <!-- 最终通知:finally里的,都要制定增强操作 
            <aop:after method="close" pointcut-ref="txManagerPoint"/>-->
            <!-- 环绕通知:前4个的综合,环绕着业务方法的增强
            <aop:around method="around" pointcut-ref="txManagerPoint"/>--> 

        </aop:aspect>
    </aop:config>   
</beans>
Test
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class AopTest {

    @Autowired
    private IEmployeeService service;
    @Test
    public void testAop(){
        service.save();
    }


}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值