Spring - 注解&代理模式&AOP

Spring - 注解 代理模式 AOP

一、Spring与导包

(一)Spring概述

  • 轻量级的DI/IOC与AOP的容器框架

(二)BeanFactory与ApplicationContext的区别

  • ApplicationContext是BeanFactory的子类,它拥有更加强大的一些方法(邮件、国际化…),BeanFactory创建的Bean默认是懒加载,ApplicationContext是迫切加载

(三)Maven导包

1.Spring和AOP需要的包
<dependencies>
    <!--Spring的核心包-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.2.5.RELEASE</version>
    </dependency>
    <!--Context包-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.2.5.RELEASE</version>
    </dependency>
    <!--aop的包-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>4.2.5.RELEASE</version>
    </dependency>
    <!--切面的一个包(织入)-->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.9</version>
    </dependency>
    <!-- Spring的测试包 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>4.2.5.RELEASE</version>
        <!--scope:范围,只能在test包中使用-->
        <scope>test</scope>
    </dependency>
    <!--junit的测试支持-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
</dependencies>
2.引入一些插件与资源
<build>
    <!--JDK1.8版本-->
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
    <!--把配置文件放在java包下面使用(默认不会编译)-->
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
        </resource>
        <resource>
            <directory>src/test/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
        </resource>
    </resources>
</build>

二、依赖注入

(一)构造参数注入

  • 标签: constructor-arg
1.根据构造器参数的顺序(索引)
<!-- 按照索引注入,索引开始为0 -->
<bean id="myBean" class="com.lty._03constructor.MyBean">
    <constructor-arg index="0" value="猪皮"></constructor-arg>
    <constructor-arg index="1" value="2"></constructor-arg>
</bean>
2.根据构造器参数的名称
<!-- 按照名称注入,名称必须一致 -->
<bean id="myBean" class="com.lty._03constructor.MyBean">
    <constructor-arg name="name" value="猪猪"></constructor-arg>
    <constructor-arg name="age" value="1"></constructor-arg>
</bean>
3.根据构造器的类型注入
<!-- 按照类型注入,必须一一对应,不能有重复的类型-->
<bean id="myBean" class="com.lty._03constructor.MyBean">
    <constructor-arg type="java.lang.String" value="甫甫"></constructor-arg>
    <constructor-arg type="java.lang.Integer" value="3"></constructor-arg>
</bean>
4.自动进行注入
<!-- 按照自动注入,顺序是不允许修改的-->
<bean id="myBean" class="com.lty._03constructor.MyBean">
    <constructor-arg value="中分"></constructor-arg>
    <constructor-arg value="4"></constructor-arg>
</bean>

(二)有一个参数是我们自己的一个对象

1.外部bean引用
<bean id="otherBean" class="com.lty._03constructor.OtherBean"></bean>
<bean id="myBean" class="com.lty._03constructor.MyBean">
    <constructor-arg index="0" value="白白"></constructor-arg>
    <constructor-arg index="1" value="2"></constructor-arg>
    <!--外部bean引用,相当于java中的全局变量,可以重复使用-->
    <constructor-arg ref="otherBean"></constructor-arg>
</bean>
2.内部bean配置
<bean id="otherBean" class="com.lty._03constructor.OtherBean"></bean>
<bean id="myBean" class="com.lty._03constructor.MyBean">
    <constructor-arg index="0" value="白白"></constructor-arg>
    <constructor-arg index="1" value="2"></constructor-arg>
    <!--内部bean配置,相当于java中的局部变量-->
    <constructor-arg>
        <bean class="com.lty._03constructor.OtherBean"></bean>
    </constructor-arg>
</bean>

(三)属性注入

1.普通属性

准备属性

private Long id;
private String name;
private Boolean sex;
private BigDecimal salary;

配置的代码

<property name="id" value="1"></property>
<property name="name" value="猪皮"></property>
<property name="sex" value="true"></property>
<property name="salary" value="3000"></property>

2.集合属性
▪ List< String>

准备属性

private List<String> list;

配置的代码

<!--List<String> list:有序可重复-->
<property name="list">
    <list>
        <value>甫甫</value>
        <value>白白</value>
        <value>中分</value>
    </list>
</property>

▪ Set< String>

准备属性

private Set<String> set;

配置的代码

<!--Set<String> set:无序不可重复-->
<property name="set">
    <set>
        <value>金木研</value>
        <value>利世</value>
        <value>董香</value>
    </set>
</property>

▪ List< OtherBean>

准备属性

private List<OtherBean> otherBeanList;

配置的代码

<!--List<OtherBean> otherBeanList
	有4个值,外部引用的地址值一样
-->
<property name="otherBeanList">
    <list>
        <!--内部引用-->
        <bean class="com.lty._04di.OtherBean"></bean>
        <bean class="com.lty._04di.OtherBean"></bean>
        <!--外部引用-->
        <ref bean="otherBean"></ref>
        <ref bean="otherBean"></ref>
    </list>
</property>

▪ Set< OtherBean>

准备属性

private Set<OtherBean> otherBeanSet;

配置的代码

<!--Set<OtherBean> otherBeanSet
	有3个值,外部引用的地址值只显示了一个
-->
<property name="otherBeanSet">
    <set>
        <bean class="com.lty._04di.OtherBean"></bean>
        <bean class="com.lty._04di.OtherBean"></bean>
        <!--外部引用-->
        <ref bean="otherBean"></ref>
        <ref bean="otherBean"></ref>
    </set>
</property>

▪ Map<String,Integer>

准备属性

private Map<String,Integer> map;

配置的代码

<!--Map<String,Integer> map-->
<property name="map">
    <map>
        <entry key="银时" value="2"></entry>
        <entry key="神乐" value="4"></entry>
        <entry key="新八" value="6"></entry>
    </map>
</property>

3.数组属性

准备属性

private String[] arrays1;
private String[] arrays2;

配置的代码

<!--String[] arrays1:标准写法-->
<property name="arrays1">
    <array>
        <value></value>
        <value></value>
    </array>
</property>
<!--String[] arrays2:简写形式-->
<property name="arrays2" value="喵咪,老师"></property>

4.Properties属性

准备属性

private Properties props1;
private Properties props2;

配置的代码

<!--Properties props1:标准写法-->
<property name="props1">
    <props>
        <prop key="username"></prop>
        <prop key="password">123456</prop>
    </props>
</property>
<!--Properties props2:简写形式(不支持中文,可以把等号换成空格)-->
<property name="props2">
    <value>
        username=瑶
        password=112233
    </value>
</property>

三、XML自动注入(了解)

  • 自动注入有两种方式 (类型与名称)
  • 设置全局的自动注入 <beans ... default-autowire="byType/byName">
  • 单独为某一个bean配置自动注入 <bean ... autowire="byType/byName">

四、全注解

1.配置context命名空间

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       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
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd
">

2.配置让Spring扫描类与支持注解

<context:component-scan base-package="com.lty._05anno"></context:component-scan>

3.在相应的类上加注解

  • @Controller:控制层
  • @Service:业务层
  • @Repository:持久层
  • @Component:组件(一个bean不知道在哪一层用这个)
  • @Autowired:注入功能

4.解决接口有多个实现

▪ 先类型注入,再根据名称注入
@Service
public class UserServiceImpl implements IUserService {
    /*注解的bean有默认名称,实现类名称首字母小写*/
    @Autowired
    IUserDao userDaoJDBCImpl;
}

▪ 修改bean的名称
@Repository("userDaoJDBC")
public class UserDaoJDBCImpl implements IUserDao{

    @Override
    public void save() {
        System.out.println("UserDaoJDBCImpl : save");
    }
}
@Autowired
    IUserDao userDaoJDBC;
}

▪ 在注入bean的时候加上一个限定注解
@Service
public class UserServiceImpl implements IUserService {
    @Autowired
    @Qualifier("userDaoJDBC")
    IUserDao userDaoJDBCImpl;
}

▪ 使用@Resource
@Service
public class UserServiceImpl implements IUserService {
    @Resource(name = "userDaoJDBCImpl")
    IUserDao userDao;
}

五、代理模式

  • 开发术语:抽象主题角色、代理主题(Proxy)角色、真实主题角色
  • 分为静态与动态
  • Spring使用的是动态代码:JDK(接口)/CGLIB
  • 动态代理的代码
//通过JDK的方案创建一个动态代理对象呢
/**
 * Foo f = (Foo) Proxy.newProxyInstance(
   Foo.class.getClassLoader(),
   new Class[] { Foo.class },
   handler);
 */
/**
 * newProxyInstance:创建代理对象
 *      参数一 ClassLoader loader :传入类加载器(随便找一个给它就可以)
 *      参数二  Class<?>[] interfaces:抽象主题角色(就是接口对应的类)
 *             userService.getClass().getInterfaces()
 *      参数三  InvocationHandler h:处理器(由我们自己实现)
 */
IUserService proxy = (IUserService)Proxy.newProxyInstance(
    ProxyTest.class.getClassLoader(),
    userService.getClass().getInterfaces(),
    new InvocationHandler() {
        //实现的代码
        /**
         * @param proxy : 代理对象(不用它)
         * @param method : 执行方法
         * @param args : 执行方法的参数
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object result = null;
            try {
                txManager.begin();
                //通过反射执行方法
                result = method.invoke(userService, args);
                txManager.commit();
            } catch (Exception e) {
                txManager.rollback();
                e.printStackTrace();
            }  finally {
                txManager.close();
            }
            return result;
        }
    }
);
proxy.save();
}

六、Spring的AOP

  • 可以用于事务管理日志管理性能监测
  • Spring实现Aop有两种方案:JDK(若目标对象实现了若干接口)与CGLIB(若目标对象没有实现任何接口)

(一)Xml版实现AOP

准备接口:IUserService

public interface IUserService {
    void save();
    void delete();
}

准备实现 UserServiceImpl

public class UserServiceImpl implements IUserService {
    @Override
    public void save() {
        System.out.println("UserServiceImpl:save");
    }

    @Override
    public void delete() {
        System.out.println("UserServiceImpl:delete");
        int i = 1 / 0;
    }

}

事务管理器对象(模拟的)

public class TxManager {
    public void begin(){
        System.out.println("开启事务");
    }
    public void commit(){
        System.out.println("提交事务");
    }
    public void rollback(Throwable throwable){
        System.out.println("回滚事务    原因 : " + throwable.getMessage());
    }
    public void close(){
        System.out.println("关闭事务");
    }
    
}

1.添加aop命名空间
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
">

2.准备两个bean
<!--创建一个业务对象-->
<bean id="userService" class="com.lty._01aopxml.service.impl.UserServiceImpl"></bean>
<!--创建一个事务对象-->
<bean id="txManager" class="com.lty._01aopxml.TxManager"></bean>

3.xml配置
<aop:config>
    <!--
            aop:pointcut  配置切点
                id  切点名称(可以随便取)
                expression  表达式execution(),定位到接口它的实现也全部找到
                    *:任意返回值
                    com.lty._01aopxml.service:定位的包名
                    I*Service:以I开始以Service结尾的所有接口类
                    *:任意方法
                    (..):任意参数
        -->
    <aop:pointcut id="pointcut" expression="execution(* com.lty._01aopxml.service.I*Service.*(..))"></aop:pointcut>
    <!--
            aop:aspect  切面(由切点与增强【通知】组成)
            ref="txManager"  引入增强的类
            	何地:在哪些类的哪些方法中:pointcut
            	何时:在方法执行之前:before
            	做什么事:执行txManager这个bean中的方法
        -->
    <aop:aspect ref="txManager">
        <!-- 前置通知 -->
        <aop:before method="begin" pointcut-ref="pointcut"></aop:before>
        <!-- 后置通知 -->
        <aop:after-returning method="commit" pointcut-ref="pointcut"></aop:after-returning>
        <!-- 异常通知(异常抛出去才能使用) -->
        <aop:after-throwing method="rollback" pointcut-ref="pointcut" throwing="throwable"></aop:after-throwing>
        <!-- 最终通知 -->
        <aop:after method="close" pointcut-ref="pointcut"></aop:after>
    </aop:aspect>
</aop:config>

环绕通知
  • 前面的4个通知就不用了,其他一样

事务管理器对象(模拟的)

public class TxManager {
    public void begin(){
        System.out.println("开启事务");
    }
    public void commit(){
        System.out.println("提交事务");
    }
    public void rollback(Throwable throwable){
        System.out.println("回滚事务    原因 : " + throwable.getMessage());
    }
    public void close(){
        System.out.println("关闭事务");
    }

    /*环绕通知*/
    public void around(ProceedingJoinPoint joinPoint){
        try{
            begin();
            //执行方法
            joinPoint.proceed();
            commit();
        }catch (Throwable throwable){
            rollback(throwable);
            throwable.printStackTrace();
        }finally {
            close();
        }
    }
}

xml配置

<aop:aspect ref="txManager">
    <!--环绕通知(可以自己控制执行顺序)-->
    <aop:around method="around" pointcut-ref="pointcut"></aop:around>
</aop:aspect>

(二)注解版实现AOP

  • 需要在相应的bean上加注解
  • 配置包的扫描
  • 所有的配置都是在TxManager加注解

xml配置

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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
       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
">

    <!--开启扫描包-->
    <context:component-scan base-package="com.lty._02aopanno"></context:component-scan>
    <!--支持AOP注解-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

事务管理器TxManager

  • 切点的名字是方法名()
/**
 * @Aspect = <aop:aspect ref="txManager">
 */
@Component
@Aspect
public class TxManager {
    /*配置一个切点(随便写个方法)
     *<aop:pointcut id="pointcut()" expression="execution()"></aop:pointcut>
     */
    @Pointcut("execution(* com.lty._02aopanno.service.I*Service.*(..))")
    public void pointcut(){

    }
    /*<aop:before method="begin" pointcut-ref="pointcut"></aop:before>*/
    @Before("pointcut()")
    public void begin(){
        System.out.println("开启事务");
    }
    /*<aop:after-returning method="commit" pointcut-ref="pointcut"></aop:after-returning>*/
    @AfterReturning("pointcut()")
    public void commit(){
        System.out.println("提交事务");
    }
    /*<aop:after-throwing method="rollback" pointcut-ref="pointcut" throwing="throwable"></aop:after-throwing>*/
    @AfterThrowing(value = "pointcut()",throwing = "throwable")
    public void rollback(Throwable throwable){
        System.out.println("回滚事务    原因 : " + throwable.getMessage());
    }
    /*<aop:after method="close" pointcut-ref="pointcut"></aop:after>*/
    @After("pointcut()")
    public void close(){
        System.out.println("关闭事务");
    }
}

环绕通知
  • 要把其它几个通知的注解去掉(不然会出现重复)
/**
 * @Aspect = <aop:aspect ref="txManager">
 */
@Component
@Aspect
public class TxManager {
    public void pointcut(){}
    
    public void begin(){
        System.out.println("开启事务");
    }

    public void commit(){
        System.out.println("提交事务");
    }

    public void rollback(Throwable throwable){
        System.out.println("回滚事务    原因 : " + throwable.getMessage());
    }

    public void close(){
        System.out.println("关闭事务");
    }

    /*环绕通知
     *<aop:around method="around" pointcut-ref="pointcut"></aop:around>
     */
    @Around("pointcut()")
    public void around(ProceedingJoinPoint joinPoint){
        try {
            begin();
            joinPoint.proceed();
            commit();
        }catch (Throwable throwable){
            rollback(throwable);
            throwable.printStackTrace();
        }finally {
            close();
        }
    }
}

七、创建Bean的方式

(一)实例化一个有公共无参构造的方式

<bean id="myBean" class="cn.itsource._09_createbean._01_base.MyBean" />

(二)FactoryBean方式

  • 一个类实现了FactoryBean接口
  • 执行getObject方式,返回的值也会变成一个Bean

准备一个FactoryBean

/**
 * 一个类实现FactoryBean接口,那么它就是一个FactoryBean
 *  泛型就是它要操作的那个类型
 */
public class EntityManagerFactoryBean implements FactoryBean<EntityManagerFactory> {

    //这个方法返回什么对象,我们拿到的bean就是什么对象
    @Override
    public EntityManagerFactory getObject() throws Exception {
        return Persistence.createEntityManagerFactory();
    }

    //返回的对象类型
    @Override
    public Class<?> getObjectType() {
        return EntityManagerFactory.class;
    }

    //这个对象是否是单例的
    @Override
    public boolean isSingleton() {
        return true;
    }
}

配置对应的方法

<bean id="entityManagerFactory" class="cn.itsource._09_createbean._02_factorybean.MyEntityManagerFactoryBean">
</bean>

BeanFactory与FactoryBean的区别
  • BeanFactory接口 : 顶层父工厂,容器,获取bean的实例
  • FactoryBean接口:实例化不能通过默认无参构造方法获取的bean,通过子类的getObject方法来返回实例

(三)集成静态简单工厂

  • 工厂中有一个静态方法
  • 直接拿到这个方法中返回的对象(bean)

准备一个静态工厂

public class DaoFactory {
    //在这个工厂中有一个静态方法
    public static MyDao createMyDao(){
        return new MyDao();
    }
}

配置这个工厂对应的方法

<bean id="myDao" class="cn.itsource._10_bean.DaoFactory"factory-method="createMyDao"></bean>

(四)集成实例简单工厂

  • 工厂中有个方法
  • 直接拿到这个方法中返回的对象(bean)

准备一个静态工厂

public class DaoFactory {
    public MyDao createMyDao(){
        return new MyDao();
    }
}

配置这个工厂对应的方法

<!--工厂的一个方法(非静态)-->
<bean id="daoFactory" class="cn.itsource._10_bean.DaoFactory" />
<bean id="myDao" factory-bean="daoFactory" factory-method="createMyDao" />
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值