spring的IOC控制反转和AOP面向切面(动态代理的实现以及Log4j)

IOC控制反转

概念:org.springframework.context.ApplicationContext接口代表 Spring IoC 容器,**负责实例化、配置和组装 bean。**容器通过读取配置元数据来获取有关要实例化、配置和组装哪些对象的指令。配置元数据以 XML、Java 注释或 Java 代码表示。IOC是一种思想,依赖注入DI是实现spring的ioc容器的一种方式。
IOC容器可以帮助实例化对象,通过注入的方式。
注入可以分为:

  1. 构造器注入
  2. 依赖注入(set方式进行注入)
  3. 拓展注入
    c命名空间
    p命名空间
    分别在spring配置文件中添加配置xmlns:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p"
IOC案例
 <!--配置自动装配
     xmlns:context="http://www.springframework.org/schema/context"
     http://www.springframework.org/schema/context
     https://www.springframework.org/schema/context/spring-context.xsd
    -->
    <!--开启自动装配 <context:annotation-config/>-->
    <!--引入p命名空间 xmlns:p="http://www.springframework.org/schema/p"-->
    <!--引入c命名空间 xmlns:c="http://www.springframework.org/schema/c"-->
    <!--导入其他资源包 <import resource="beans.xml"/>-->
<!--注册bean-->
  1. 配置环境maven
		<dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.9.RELEASE</version>
        </dependency>
  1. 编写Java实体类
    Pet.java
package cn.supperbro.domain;

/**
 * 一个pet实体类
 */
public class Pet {
    private String name;
    private int age;

    public Pet() {
    }

    public Pet(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Pet{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

User.java

package cn.supperbro.domain;

import java.util.*;

/**
 * 一个user实体类
 */
public class User {
    /**
     * 包含基本类型,集合类型,数组,对象
     */
    private String name;
    private String[] nick;
    private List<String> hobbies;
    private Map<Object,Object> friends;
    private Set<String> telephone;
    private Properties address;
    private Pet pet;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String[] getNick() {
        return nick;
    }

    public void setNick(String[] nick) {
        this.nick = nick;
    }

    public List<String> getHobbies() {
        return hobbies;
    }

    public void setHobbies(List<String> hobbies) {
        this.hobbies = hobbies;
    }

    public Map<Object, Object> getFriends() {
        return friends;
    }

    public void setFriends(Map<Object, Object> friends) {
        this.friends = friends;
    }

    public Set<String> getTelephone() {
        return telephone;
    }

    public void setTelephone(Set<String> telephone) {
        this.telephone = telephone;
    }

    public Properties getAddress() {
        return address;
    }

    public void setAddress(Properties address) {
        this.address = address;
    }

    public Pet getPet() {
        return pet;
    }

    public void setPet(Pet pet) {
        this.pet = pet;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", nick=" + Arrays.toString(nick) +
                ", hobbies=" + hobbies +
                ", friends=" + friends +
                ", telephone=" + telephone +
                ", address=" + address +
                ", pet=" + pet +
                '}';
    }
}
  1. 配置applicationContext.xml
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--使用有参构造器注入pet-->
    <bean id="pet" class="cn.supperbro.domain.Pet">
        <!--可以选择index下标 name type参数类型进行参数赋值-->
        <constructor-arg index="0" value="喵喵"/>
        <constructor-arg name="age" value="2"/>
    </bean>
<!--使用依赖注入user-->
    <bean id="user" class="cn.supperbro.domain.User">
        <property name="name" value="明天"/>
        <!--数组赋值-->
        <property name="nick">
            <array>
                <value>小明</value>
                <value>小天</value>
            </array>
        </property>
        <!--list集合-->
        <property name="hobbies">
            <list>
                <value>篮球*1</value>
                <value>篮球*2</value>
            </list>
        </property>
        <!--map集合-->
        <property name="friends">
            <map>
                <entry key="好朋友" value="今天"/>
                <entry key="女朋友" value="昨天"/>
            </map>
        </property>
        <!--set集合-->
        <property name="telephone">
            <set>
                <value>1233654789</value>
                <value>zxcedfsfsd</value>
            </set>
        </property>
        <!--prop-->
        <property name="address">
            <props>
                <prop key="新地址">china</prop>
                <prop key="旧地址">old china</prop>
            </props>
        </property>
        <!--对象 通过引用-->
        <property name="pet" ref="pet"/>
    </bean>

</beans>
  1. 测试
import cn.supperbro.domain.Pet;
import cn.supperbro.domain.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    @org.junit.Test
    public void testBean(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Pet pet = context.getBean("pet", Pet.class);
        User user = context.getBean("user", User.class);
        System.out.println(pet);
        System.out.println("-------------------------");
        System.out.println(user);
    }
/*
    Pet{name='喵喵', age=2}
    -------------------------
    User{name='明天', nick=[小明, 小天], hobbies=[篮球*1, 篮球*2],
    friends={好朋友=今天, 女朋友=昨天}, telephone=[1233654789, zxcedfsfsd],
    address={新地址=china, 旧地址=old china}, pet=Pet{name='喵喵', age=2}}
*/
}

通过注解也可以配置

在spring4之后,要使用注解开发,必须要导入aop的包,使用注解导入context约束。可以配置注解扫描的包

<context:component-scan base-package="cn.supperbro.domain"/>
  1. bean

    @Component :组件 ;作用于类上;相当于创建一个bean

    @Value:作用于属性上或者是set方法上,相当于给bean赋值

  2. 衍生的注解

    MVC三层架构分层

    Dao:@Repository

    Service:@Service

    Controller:@Colltroller

    功能都是一样的,将其作用的类注册到Spring的IOC容器中,装配

  3. @Scope("…")作用在类上,定义其作用域

package cn.supperbro.domain;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class Student {
    @Value("supperbro")
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

总结

简单介绍到了IOC的基本使用,当然还有bean的作用域,自动装配,注解开发等等…
参照官网吧

AOP面向切面

代理模式

静态代理

当然在使用spring的aop进行切面编程也是要进行方法增强必须要了解代理模式啦
静态代理描述
角色分析:

1. 抽象角色:一般会通过接口或者抽象类
2. 真实角色:被代理的角色
3. 代理角色:代理真实角色,一般带有附属属性
4. 客户端角色:访问代理角色

代理模式的好处:

  1. 可以是真实角色的操作更加纯粹!不用去关注一些公共的业务
  2. 公共任务交给代理角色,实现了业务的分工
  3. 公共业务发生了拓展时,方便集中管理

缺点:

  1. 一个真实角色就会产生一个代理角色,代码量大。
动态代理

动态代理和静态代理角色一样

动态代理的代理类时自动生成的

动态代理:

  1. 基于接口实现的动态代理—JDK的动态代理
  2. 基于类的动态代理—cglib/Java字节码JAVAAssis

通过InvocationHandler代码实现动态代理

  • 抽象对象
package cn.supperbro.proxy;

public interface Sent {
    public void sent();
}
  • 真实对象
package cn.supperbro.proxy;

public class Host implements Sent{
    @Override
    public void sent() {
        System.out.println("房东要卖房子...");
    }
}
  • 动态代理生成代理类
package cn.supperbro.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyTest implements InvocationHandler {
    //定义要被代理的抽象角色
    private Object abstractCharacter;
    //set方法赋值
    public void setAbstractCharacter(Object abstractCharacter) {
        this.abstractCharacter = abstractCharacter;
    }
    public ProxyTest() {
    }
    //或者有参构造赋值
    public ProxyTest(Object abstractCharacter) {
        this.abstractCharacter = abstractCharacter;
    }
    //生成代理类 需要用到类Proxy
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), abstractCharacter.getClass().getInterfaces(),this);
    }
    //执行生成代理类的方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object invoke = method.invoke(abstractCharacter, args);
        add();//方法需要添加才可以被使用
        return invoke;
    }
    public void add(){
        System.out.println("代理类自带的方法");
    }
}
  • 客户端
 package cn.supperbro.proxy;
//客户端
public class Client {
    public static void main(String[] args) {
        //创建真实对象
        Host host = new Host();
        //使用动态生成器进行代理类的生成
        ProxyTest pid = new ProxyTest(host);
        //生成代理类
        Sent proxy = (Sent) pid.getProxy();
        proxy.sent();
    }
}

也可以注册到IOC中…

AOP概念

AOP(Aspect Orient Programming)也就是面向切面编程,作为面向对象编程的一种补充,已经成为一种比较成熟的编程方式。其实AOP问世的时间并不太长,AOP和OOP互为补充,面向切面编程将程序运行过程分解成各个切面。AOP专门用于处理系统中分布于各个模块(不同方法)中的交叉关注点的问题,在JavaEE应用中,常常通过AOP来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等,AOP已经成为一种非常常用的解决方案。

  • 切面(Aspect): 切面用于组织多个Advice,Advice放在切面中定义。
  • 连接点(Joinpoint): 程序执行过程中明确的点,如方法的调用,或者异常的抛出。在Spring AOP中,连接点总是方法的调用。
  • 增强处理(Advice): AOP框架在特定的切入点执行的增强处理。处理有"around"、"before"和"after"等类型
  • 切入点(Pointcut): 可以插入增强处理的连接点。简而言之,当某个连接点满足指定要求时,该连接点将被添加增强处理,该连接点也就变成了切入点。
实现方法

在实现AOP测试入门案例时,方法增强作用于日志输出,所以会用到log4j日志。
环境配置

		<dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>

log4j的配置文件

# Root logger option
log4j.rootLogger=DEBUG,console,file

# 输出到控制台的相关的配置
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
# 输出到文件的相关配置
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.file=./log/log.log
log4j.appender.file.MaxFileSize=10MB
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

#日志输出的级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG

方式一通过实现接口的方式

  1. 切点类
    接口 ServiceTest.java
package cn.supperbro.service;

public interface ServiceTest {
    void add();
    void delete();
}

实现类 ServiceTestImpl.java

package cn.supperbro.service.impl;

import cn.supperbro.service.ServiceTest;

public class ServiceTestImpl implements ServiceTest {
    @Override
    public void add() {
        System.out.println("增加了一个用户");
    }
    @Override
    public void delete() {
        System.out.println("删除了一个用户");
    }
}
  1. 方法增强
    创建切面类 AddLog.java
    通过实现接口来实现AOP
package cn.supperbro.log;

import org.apache.log4j.Logger;
import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class AddLog implements AfterReturningAdvice {
    //实现接口的方式:afterReturningAdvice表示的是切点方法之后执行该方法

    /**
     *
     * @param o 切点对象返回的值
     * @param method 切点的方法
     * @param objects args参数
     * @param o1 表示切点本身
     * @throws Throwable
     */
    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        Logger logger = Logger.getLogger(AddLog.class);
        logger.info(o1.getClass().getName()+"执行了"+method.getName()+"方法"+";返回的参数是:"+o);
    }
}
  1. 配置
    关于execution表达式
    在这里插入图片描述
<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

 <bean id="serviceTest" class="cn.supperbro.service.impl.ServiceTestImpl"/>
    <bean id="addLog" class="cn.supperbro.log.AddLog"/>
    <aop:config>
        <!--切入点-->
        <aop:pointcut id="testPoint" expression="execution(* cn.supperbro.service.impl.ServiceTestImpl.*(..))"/>
        <!--引入方法增强切面-->
        <aop:advisor advice-ref="addLog" pointcut-ref="testPoint"/>
    </aop:config>
</beans>
  1. 测试
public class Test {
    @org.junit.Test
    public void testBean(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        ServiceTest test = context.getBean("serviceTest", ServiceTest.class);
        test.add();
    }
    /*增加了一个用户
[cn.supperbro.log.AddLog]-cn.supperbro.service.impl.ServiceTestImpl执行了add方法;返回的参数是:null*/
}

实现方式二
自定义切面 功能相对于实现接口的功能较差。
切面

package cn.supperbro.log;

import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.runtime.internal.AroundClosure;

/**
 * 自定义切面
 */
public class DivProxy {
    public void after(){
        Logger logger = Logger.getLogger(DivProxy.class);
        logger.info("在方法执行以后执行");
    }
    //环绕增强
    Logger logger = Logger.getLogger(DivProxy.class);
    public Object around(ProceedingJoinPoint point) throws Throwable {
        logger.info("在方法执行前");
        //切入点
        Object proceed = point.proceed();
        logger.info("在方法执行后");
        return proceed;
    }
}

配置

<aop:config>
        <!--切入点-->
        <aop:pointcut id="testPoint" expression="execution(* cn.supperbro.service.impl.ServiceTestImpl.*(..))"/>
        <!--
        通知-->
        <aop:aspect id="div" ref="divProxy">
            <aop:around method="around" pointcut-ref="testPoint"/>
            <aop:after method="after" pointcut-ref="testPoint"/>
        </aop:aspect>
    </aop:config>

测试

 @org.junit.Test
    public void test2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
       // DivProxy divProxy = context.getBean("divProxy", DivProxy.class);
        ServiceTest test = context.getBean("serviceTest", ServiceTest.class);
        test.delete();
        test.add();
    }
    /*
    [cn.supperbro.log.DivProxy]-在方法执行前
    删除了一个用户
    [cn.supperbro.log.DivProxy]-在方法执行后
    [cn.supperbro.log.DivProxy]-在方法执行以后执行
    [cn.supperbro.log.DivProxy]-在方法执行前
    增加了一个用户
    [cn.supperbro.log.DivProxy]-在方法执行后
    [cn.supperbro.log.DivProxy]-在方法执行以后执行
     */
}

方式三 通过注解配置

  1. 创建接口和目标类

```java
package cn.supperbro.annotation;

public interface Target {
    void add();
}
package cn.supperbro.annotation;

import org.springframework.stereotype.Component;

@Component("target")
public class TargetImpl implements Target {
    @Override
    public void add() {
        System.out.println("增加了");
    }
}
  1. 创建切面类
  2. 将目标和切面类的对象创建权交给spring
  3. 在切面类中进行使用注解配置织入关系
package cn.supperbro.annotation;

import org.apache.log4j.Logger;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;



@Component("annotation")
@Aspect
public class ProxyAnno {
    @Before("execution(* cn.supperbro.annotation.TargetImpl.*(..))")
    public void before(){
        Logger logger = Logger.getLogger(ProxyAnno.class);
        logger.info("方法前");
    }
}
  1. 在配置文件中开启组件扫描和AOP的自动代理
<context:component-scan base-package="cn.supperbro.annotation"/>

<!--aop自动代理-->
<aop:aspectj-autoproxy/>
  1. 测试
@org.junit.Test
    public void testBean(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Target target = (Target) context.getBean("target");
        target.add();
    }
    /*
    [cn.supperbro.annotation.ProxyAnno]-方法前
    增加了
     */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值